Managing Background Job Spikes with Scalingo Autoscaling
Stop paying for idle background workers. Learn how to use Scalingo's queue-based autoscaling to dynamically adjust worker dynos based on real-time job volume.
10 Jun 2026, 07:41 UTC

The Cost of Over-Provisioning Workers
Engineering teams often face a dilemma when managing background workers: provision for the peak load and pay for idle resources 90% of the time, or provision for the average load and risk a massive backlog during traffic spikes. When a job queue (like Sidekiq or Resque) grows faster than workers can process it, latency increases, and user-facing features—like welcome emails or report generation—begin to lag.
The solution is to shift from static dyno counts to a policy-driven approach where the infrastructure reacts to the actual volume of pending work. By tying the number of active worker dynos to the queue depth, you can maintain a lean baseline while automatically expanding capacity only when the workload demands it.
How Queue-Based Autoscaling Works
Scalingo's autoscaling policy monitors a specific job queue and compares the current depth (the number of pending jobs) against a user-defined threshold. Unlike CPU-based scaling, which can be misleading if workers are waiting on I/O, queue-depth scaling is a direct proxy for pending work.
The Scaling Logic
- Minimum Dynos: The baseline capacity that always remains active to ensure immediate processing of low-volume traffic.
- Maximum Dynos: A safety ceiling that prevents runaway costs or database connection exhaustion during an unexpected surge.
- Threshold: The number of jobs per dyno that triggers a scale-up event. For example, if your threshold is 10 and you have 1 dyno but 20 jobs, the system will trigger an increase.
- Cooldown Period: A mandatory wait time between scaling actions. This prevents "flapping," where the system rapidly adds and removes dynos due to minor fluctuations in queue length.
Implementing a Scaling Policy
Configuration is handled via the Scalingo CLI. To implement this, you need administrative permissions for the application and the name of the queue you wish to monitor.
Example Configuration:
Assume you have a Sidekiq queue where you want to maintain a maximum of 10 jobs per worker, with a minimum of 1 worker and a maximum of 5.
# Run this command from your local terminal with the Scalingo CLI installed
scalingo scaling-policy set --queue sidekiq --min 1 --max 5 --threshold 10 --cooldown 60
Expected Behavior:
- If the queue length hits 11, Scalingo will spin up a second dyno.
- If the queue drops to 0 and stays there for 60 seconds (the cooldown), the system will scale back down toward the minimum of 1.
- If the queue hits 50, the system will scale up to the maximum of 5 dynos and stop there.
Verification and Diagnostics
Because scaling happens asynchronously, you should verify the behavior through metrics and logs rather than assuming the command worked based on the CLI output alone.
1. Log Monitoring: Run the following command to watch scaling events in real-time:
scalingo logs -f
Look for entries explicitly stating "scaling up dyno X" or "scaling down dyno Y". These logs confirm that the policy engine has triggered an action based on the queue depth.
2. Metrics Validation: Access the Scalingo dashboard metrics page. You should see a correlation between the Queue Depth graph and the Dyno Count graph. If the queue depth rises but the dyno count remains flat, check if you have hit your application's hard cap for total dynos.
Trade-offs and Constraints
Queue-based scaling is powerful, but it is not a silver bullet. Consider these limitations during your design phase:
- Job Duration vs. Queue Depth: If your jobs are extremely long-running (e.g., processing a 1GB video file), the queue depth may remain high even if all workers are fully utilized. This can lead to "over-provisioning" where the system adds more dynos that simply sit in a queue waiting for the same slow resource.
- Idempotency Requirements: When scaling down, workers may be terminated. Ensure your background jobs are idempotent (meaning they can be run multiple times without changing the result beyond the initial application). If a worker is killed mid-job, the job will likely be retried by another worker.
- Database Connections: Every new worker dyno consumes database connections. If your
max-dynossetting is too high, you may crash your database by exceeding itsmax_connectionslimit before you hit the Scalingo dyno limit.
Actionable Summary
To move from static to autoscaling workers, start by analyzing your average and peak queue depths over a one-week period. Set your --min to your average load and your --max to a value that your database can safely support. Always implement a cooldown of at least 60 seconds to maintain environment stability.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.