Optimizing Application Workloads
When an application starts hitting resource limits, increasing the container size is not always the only option. Sometimes, the issue comes from a specific workload: a long request, a background job, a large import, or too much concurrency in one process.
This page lists optimization options you can consider when you want to improve how these workloads use container resources.
For container sizing, see Choosing a Container Size. To change the number or size of running containers, see Scaling Your Application.
Design Around Process Types
Use process types to separate workloads that do not have the same
operational profile. A web process should handle HTTP requests and return
responses quickly, using background jobs for long work.
Run background workers, importers, exporters, and scheduled jobs in process types that match their role. This makes each workload easier to scale, size, and debug independently.
Typical process types include:
-
webfor HTTP traffic; -
workerfor background jobs; -
clockorschedulercustom process types for long-running, high-frequency, or precise recurring jobs; - dedicated workers for imports, exports, batch tasks, or other specialized workloads.
For most recurring jobs, consider the
Scalingo Scheduler with a cron.json file as the
built-in option for running scheduled tasks without a continuously running
process.
Consider Private Networks for Separate Applications
For larger applications, process types are not the only way to separate responsibilities. When a workload is operated as a separate application, Private Networks let application containers communicate privately and share internal services within the same project.
Private Networks are complementary to process types:
- use process types to separate workloads inside an application;
- use Private Networks when a workflow spans multiple applications within the same project.
Tune Concurrency Carefully
Concurrency lets a process handle more work in parallel, but each additional thread, worker, or child process usually consumes more memory and may increase database or external service pressure.
Tune concurrency separately for each process type:
- increase web concurrency only if response time and resource usage stay healthy under realistic traffic;
- reduce worker concurrency if occasional jobs create memory pressure;
- keep enough database connections for the configured concurrency;
- use separate process types for jobs that have different resource profiles, such as CPU-heavy and memory-heavy jobs.
Some runtimes expose Scalingo-specific or buildpack-provided defaults and environment variables. See the language pages for details: Ruby, Python, PHP, Java, Node.js, and Go.
Isolate Resource-Intensive Workloads
Resource pressure is often caused by specific workloads rather than by every request. Check whether the application consumes more CPU or memory regularly, or only during occasional tasks such as:
- background jobs;
- PDF generation;
- image or video processing;
- large imports or exports;
- report generation;
- scheduled batch tasks;
- large in-memory caches or datasets.
Depending on what you observe, prefer the smallest change that addresses the actual cause:
- optimize the code path that consumes too many resources;
- tune runtime-specific memory or concurrency settings;
- reduce worker or job concurrency;
- split large jobs into smaller chunks;
- move specialized jobs to their own process type when they do not share the same resource profile as the rest of the application.
If each container still needs more memory after these changes, continue with Choosing a Container Size.
Size and Scale Your App
Once your application is optimized for its workload:
- choose the right size for each process type;
- scale the application to match capacity to traffic;
- read Application Metrics and configure alerts to monitor the application after changes.
If the application reaches its memory limit and crashes, see Runtime Issues for diagnosis and recovery guidance.