Cron jobs and background workers on StackBlaze
Scheduled tasks and queue consumers are first-class services, not hacks on top of a web dyno. Here is how to run them reliably.
Tom Walsh
Developer Advocate
A common anti-pattern on PaaS platforms is running cron inside your web process or using an external scheduler that HTTP-calls your API. Both approaches break under load, duplicate work across replicas, or wake your entire app just to send one email.
On StackBlaze, cron jobs and workers are separate service types with their own lifecycle, scaling rules, and deploy semantics. This tutorial shows how to set them up correctly.
Cron jobs: short-lived, scheduled
A cron service runs as a Kubernetes Job on your schedule. Only one instance runs per trigger, even if your web tier has ten replicas, you will not get ten copies of the nightly cleanup script.
services:
cleanup-stale-sessions:
type: cron
schedule: "*/15 * * * *"
build: .
start: node scripts/cleanup-sessions.js
timeout_seconds: 300
env:
DATABASE_URL:
from_service: db
property: connection_stringCron jobs must finish
If a job runs longer than timeout_seconds, it is killed and marked failed. Design idempotent jobs and log how many rows you processed so a retry does not double-apply changes.
Background workers: long-lived consumers
Workers are Deployments that do not receive HTTP traffic. They pull from Redis, SQS-compatible queues, or whatever broker you configure. Scale them on queue depth or CPU depending on your workload.
import { Worker } from 'bullmq';
import Redis from 'ioredis';
const connection = new Redis(process.env.REDIS_URL!);
const worker = new Worker(
'emails',
async (job) => {
await sendEmail(job.data);
},
{ connection, concurrency: 5 },
);
process.on('SIGTERM', async () => {
await worker.close();
process.exit(0);
}); email-worker:
type: worker
build: .
start: node dist/worker.js
scaling:
min_instances: 1
max_instances: 8
target_cpu_percent: 70
env:
REDIS_URL:
from_service: cache
property: connection_stringDeploy behavior differences
| Service type | On deploy | Grace period |
|---|---|---|
| web | Rolling update, zero-downtime | 60s default |
| worker | Rolling update, finishes in-flight jobs | 300s default |
| cron | Next run uses new image | N/A (job timeout applies) |
Observability
Cron run history appears in the dashboard: start time, duration, exit code, and logs for that execution. Workers share the same metrics and tracing as web services, filter by service name to separate worker noise from API traffic.
Treat background work as production code with the same tests, deploy process, and on-call ownership as your API. StackBlaze gives you the primitives; discipline is still on your team.
Tom Walsh
Developer Advocate at StackBlaze
Member of the founding team at StackBlaze. Writes about infrastructure, engineering culture, and the systems that keep production running.
More from the blog
How Calico network policies isolate tenants on shared hosting
Shared Kubernetes does not have to mean shared trust boundaries. Calico enforces network isolation, Linkerd provides automatic mTLS between services, and Falco detects runtime threats, three layers that keep tenants separated on shared infrastructure.
Shared platform vs dedicated clusters: control plane isolation and policy-as-code
Policy-as-code on a shared platform gives you guardrails without operational overhead. Dedicated clusters add an isolated control plane, single-tenant nodes, and customer-owned policy boundaries, here is how to choose and what changes under the hood.
Regulatory compliance and data governance on StackBlaze
SOC 2, GDPR, HIPAA-readiness, data residency, encryption, audit logs, and DPAs, a detailed map of how StackBlaze controls align with common regulatory frameworks and what you own vs what the platform certifies.