Maximizing Performance with Judoscale: Scheduling Your Scaling

Jon Sully

Jon Sully

@jon-sully

Time for our second edition of Maximizing Performance with Judoscale. This time we’re going to dig into scheduled autoscaling. We want to show you a few clever setups and situations where combining Judoscale’s typical queue-time based scaling with time-based tweaks can make for both a reliable application and great savings.

So... let’s talk about time! ⏰


Maximizing Performance with Judoscale is a series that covers all of Judoscale’s features and options. Jump to other posts here:

  1. Target Queue Time Range
  2. Scheduling your Scaling (this page!)
  3. Setting Sensitivities

Just FYI, we’re going to use the term “dyno” or “dynos” in most places here; this is Heroku’s word to represent an application container instance. Render calls these “Services” while Amazon ECS calls them “Tasks” wrapped up under a “Service”. All of the theory in this article is just the same between all three, “dyno” just remains our default phrasing.

Scheduled Scaling

Let me set a little bit of context here before we dive in. Judoscale’s primary objective is to scale your application based on queue time — either your request queue time for web dynos, or your job queue time for background-job dynos (we often call these “worker” dynos). Without any additional setup, that’s exactly what Judoscale will do! Throughout the day, 24/7, Judoscale will constantly monitor your app’s metrics and adjust the number of running dynos (your ‘current scale’) to fit your Target Queue Time Range. That is, until/unless we reach your specified minimum or maximum number (“scale limits”) of dynos you want to run on this process:

image-20240413061159557

We can think of scale limits as guard-rails for your autoscaling. In this particular example, the process can scale up but Judoscale will never scale the process higher than 3 dynos. Similarly, Judoscale will never scale the process lower than 1 dyno.

Did you know that Judoscale can scale your process lower than 1 dyno? Judoscale is able to scale your background-job processes down to zero when they’re not in use! Then, once a job is queued, it can fire the process right back up to handle the job. It’s like an automatic ‘sleep’ mode for your worker dynos 😎

So when we designed and built the schedule feature, we did it in a way that worked together with autoscaling, not against it. We didn't want a ‘schedule’ that essentially disabled autoscaling during a particular span of time — we wanted to build something that would just adjust the scale limits for a particular span of time! And that’s all it does. A schedule allows you to setup spans of time where your scale limit is overridden to a different value.

When you create a schedule, you first setup the different spans of time where you want the override to kick in. Let’s use a contrived example. Let’s say that my application is only ever really used on Wednesdays, only by users that live in Eastern Time, and only during typical business hours. In time-terms, I know that I’ll want a scale limit override to kick in from about 8am to about 5pm in EST. Our schedule override interface uses UTC to keep things simple, so we’re looking to override our scale limits from 12:00 UTC (8am Eastern) to 21:00 UTC (5pm Eastern).

So I’ll pop open our Schedule override panel and setup a single time-span that I want to override our defaults:

image-20240413065854229

Once I save that, I’ll now see two Scale Limit ranges in the Judoscale UI:

image-20240413070105844

And I can change and adjust the scale limit for the override time apart from my app’s default limit. Since this example is all about expecting users and traffic during our override, we’ll bump the values up to prepare for that traffic:

image-20240413070302333

The neat part of this (and the reason we call it ‘scheduled autoscaling’) is because autoscaling is still active during this override period, but Judoscale is aware of your new scale limits. That means that, for example, your app can happily stay at minimum scale all night (1 dyno) but Judoscale will immediately scale it up to the override-minimum (3 dynos) once it hits 12:00 UTC. Scheduled autoscaling is still queue-time autoscaling, it just changes the scale limits at a set time, for a set period.

But Why? When?

We built this feature into Judoscale because many of our customers in the early days wanted it! But why? Let’s explore a few clever ways this strategy can benefit both your application and your business.

When you know the traffic is coming ahead-of-time. If you’ve ever run any kind of e-commerce company and launched a sale, you’ll know that traffic spikes right at that moment. In fact, many businesses find the trend of ‘weekly drops’ to be extremely effective in today’s market so we see them all over the place. The idea is this: if you know the traffic is coming, setup a scaling override to accommodate that traffic pickup! Whether it’s a sale, a product launch, ticket sales, course enrollments, or anything else where you know ahead of time that you’ll have a large, sharp influx of traffic, set up an override! If you don’t, Judoscale will still scale up your dynos on a step-by-step basis, but this can still leave you with too few resources when traffic increases are sharp enough.

Let me put it in visual terms. This is what it looks like when you have a very sharp traffic increase and no override schedule. We can see the dyno count does increase over time, but it’s not enough to thwart the massive traffic increase:

image-20240425151825697

Conversely, we can see in this chart what it looks like to have a schedule override — queue time hardly even budges!

image-20240425152046082

When you have reliable daily traffic patterns. Does your application primarily serve users in only a few timezones? In one hemisphere? Is it an internal-only application generally only used during work hours? Is it a content-driven site that primarily caters to morning coffee-drinkers or afternoon-reddit-scrollers? Maybe it’s content-delivery for media that people primarily consume after work? All of these situations make great candidates for override scheduling — they all have clear, time-based, traffic patterns on a daily or weekly basis. Slightly different than the above, the focus here is on the cyclical nature of the traffic as a function of the application’s use and the slower ramp up of traffic.

These types of traffic patterns are less likely to spike traffic fast enough to where the step-by-step / typical autoscaling setup is an issue, but setting an override schedule can help you better-control the upper and lower limits of what’s considered ‘normal’ in those traffic windows.

For instance, let’s consider an internally-used application for a large company that operates only during North American work hours (8am Eastern to 5pm Pacific). During those hours, the team wants to keep a minimum dyno count of 5 and a maximum of 10. Outside of those hours, it’s okay to bring the minimum dyno count all the way down to 1. No sense in wasting resources outside of known traffic patterns! They could also lower the maximum dyno count during off-hours to help prompt alerting if traffic is abnormally high during off hours. Lots of flexibility allowed here!

image-20240425152117881

When you have batches to process! This is a similar situation as ‘when you know traffic is coming ahead of time’, but for your background jobs! If your application kicks off large batches of long-running or high-horsepower background jobs on any kind of known schedule, you can use override scheduling to your advantage! This works on both sides, too. If you want to minimize the latency and runtime of those batches, you can setup an override schedule to preemptively upscale you so that your workers can quickly parallelize and crush your job queue! On the other hand, if you’re in a period where you know you won’t be processing jobs, you can use an override schedule to allow your worker dynos to downscale all the way to zero. If a job comes up, Judoscale will spin up a dyno to execute it (this isn’t a forced ‘stay at zero’), but you have the flexibility to allow zero workers for different periods of time.

Wrapping it up

Judoscale offers you the facilities to setup a smart autoscaling schedule based on overriding your scale range for various periods of time. When considered in the scope of your application, your business, and your users, this override schedule can be a simple way to ensure that your application’s resources are pre-set for success, even while auto-scaling to accommodate the smaller tweaks and needs.

Whether it's anticipating a major sale, handling predictable traffic surges, or managing resource-intensive tasks, scheduled autoscaling helps your system stay resilient and responsive.


If you made it through this whole article but haven’t actually signed up for Judoscale yet... kudos! We’d recommend you check out our forever-free plan — you can have free autoscaling forever and only need to install a simple Ruby Gem, Node Package, or Python Cheese Package.

P.S. We’re around to help you through this process too! Just click the “Help” button in the Judoscale UI and pick your style!

image-20240316113003630