Background worker
A background worker is a containerized process that runs continuously on ComputeSphere without exposing a public URL. It wakes up on its own — usually because there's something to consume from a queue, a stream, a database, or a remote API — does the work, and keeps looping.
web-servicebackground-workercron-jobBackground worker is the right kind for: queue consumers, polling jobs, stream processors, ETL pipelines, AI inference workers, IoT message handlers, file processors, log shippers — anything that doesn't wait for an HTTP request to do its job.
What you configure
| Field | What it does |
|---|---|
| Name | Identifier for the worker — unique within the project. |
| Plan | Spherelet shape: flex, standard, or performance. See Spherelets. |
| Spherelets | How many copies to run in parallel (1–100). For queue consumers, more spherelets = more throughput. |
| Build source | image to pull a pre-built image, or git to build from a connected repo. |
| Image | Registry path (when build_source: image) — e.g. ghcr.io/acme/worker:1.0.0. |
| Dockerfile | Path to the Dockerfile (when build_source: git) — defaults to Dockerfile. |
| Branch | Git branch to deploy from (when build_source: git) — defaults to main. |
| Command | Optional. Overrides the container's default CMD — e.g. node workers/process-queue.js. Useful when the same image runs different worker entrypoints in different services. |
| Autoscaling | Optional. CPU-based. Set min/max spherelets and a target. See Auto-scaling. |
| Environment variables | Configuration passed into the container — queue URLs, API keys, feature flags. See Environment variables. |
Conspicuously absent compared to web service: no port, no health check path, no custom domain. A background worker doesn't accept incoming traffic, so the platform has nothing to route to it and no HTTP probe to fire.
How it differs from the other service kinds
| Aspect | Web service | Background worker | Cron job |
|---|---|---|---|
| Trigger | HTTP request | Continuous loop | Cron schedule |
| Public URL | Yes | No | No |
| Lifetime | Long-running | Long-running | One run per tick |
| Port required | Yes | No | No |
| Health check | HTTP path | Process liveness | Exit code |
| Scaling shape | More spherelets = more concurrency | More spherelets = more parallel workers | One container per tick |
| Best for | APIs, web apps | Queue consumers, polling, ETL | Scheduled batch jobs |
If your work is request-driven, use Web service. If it's on a schedule, use Cron job. Background worker fills the gap in between.
Common patterns
Queue consumer
The worker pulls messages from a queue (Valkey list, RabbitMQ, SQS, etc.) and processes them. The container's main loop blocks waiting for the next message:
// node workers/process-orders.js
import Valkey from "iovalkey";
const valkey = new Valkey(process.env.VALKEY_URL);
while (true) {
// BLPOP blocks until a message arrives, with a timeout.
const message = await valkey.blpop("orders:queue", 30);
if (!message) continue;
await processOrder(JSON.parse(message[1]));
}
Scale spherelets up for more concurrent processing. Each spherelet runs its own copy of the loop and competes for messages — most queue brokers handle the distribution automatically.
Polling worker
The worker polls a remote source (API, database, S3 bucket) on an interval. Different from cron jobs in that the worker chooses its own cadence and holds state between polls:
# python workers/sync_repos.py
import time
import requests
CURSOR = None
while True:
response = requests.get(f"https://api.github.com/.../events?since={CURSOR}")
events = response.json()
if events:
process_events(events)
CURSOR = events[-1]["timestamp"]
time.sleep(15)
Scale to one spherelet — multiple pollers would compete and duplicate work.
Stream processor
The worker subscribes to a stream (Kafka, Valkey Streams, Server-Sent Events) and processes events as they arrive. Similar to queue consumer, but the stream's ordering and replay semantics shape how you scale.
Lifecycle controls
A background worker supports the same lifecycle verbs as a web service — deploy, redeploy, restart, stop, start, rollback, scale. See Service actions.
The big behavioral difference: a restart drops in-flight work. If your worker is mid-message when its spherelet restarts, the message goes back to the queue (assuming you're using a broker with at-least-once delivery). Design your loop to be idempotent — every message processed at least once, no duplicates of side effects.
Create a background worker
- Open the project and environment where the worker should run.
- Click New service → Background worker.
- Pick a build source: Image or Git.
- Fill in name and a compute plan (Flex / Standard / Performance).
- (Optional) Override the container's default command if the image runs multiple worker entrypoints.
- (Optional) Add environment variables for queue URLs, API keys, feature flags.
- (Optional) Turn on autoscaling with a min/max range and CPU target.
- Click Create.
The worker appears in the Services tab alongside web services and cron jobs.
Honest limits
- No graceful drain. When a worker is stopped, restarted, or redeployed, the platform sends
SIGTERMand gives the process a short window to exit beforeSIGKILL. Long-running message processing should checkpoint progress and tolerate being interrupted. - No retries on the platform side. If a worker crashes, the spherelet restarts — but the message it was processing is broker-side. Use a broker with delivery guarantees (RabbitMQ ack, SQS visibility timeout, Kafka offset commits) so you don't lose work.
- CPU-only autoscaling. Memory pressure, queue depth, and message age aren't autoscaling signals today. Scale on those manually, or trigger scale from a separate metric pipeline.
- One command per worker. If you want the same image to run a queue consumer AND a polling worker, create two background workers in the same project — they share the image, each has its own
command.
What's next
- Web service — for request-driven HTTP work.
- Cron jobs — for scheduled, one-shot work.
- Datastores — Valkey, Postgres, RabbitMQ. Workers usually run against one of these.
- Environment variables — how queue URLs and secrets land in your worker.
- Auto-scaling — CPU-based scaling for parallel workers.