Service · Worker

Deploy a worker.

A worker on HostingGuru is a long-running background process — no public URL, no health endpoint required. The right service type for queue consumers (BullMQ, Sidekiq, Celery, RQ), scheduled job runners, data pipelines, websocket fan-out servers, and anything else that needs to keep running but doesn't speak HTTP to the public internet.

How it works

From repo to a running worker

Worker process running in the background

1. Pick "Worker"

From the dashboard, click New service → Worker. Pick the repo, branch, and root directory. We auto-detect Node, Python, Go, Ruby, Rust, Java, and PHP. The build phase is identical to the API service type — only the start phase and networking differ.

2. Set the start command

Common shapes: node dist/worker.js, python -m app.worker, celery -A app worker --loglevel=info, bundle exec sidekiq, ./bin/processor. The process runs as PID 1 of its container — when it exits, the container is considered stopped.

3. Add env vars + connect resources

Workers usually need a queue (Redis), a database (Postgres), and credentials for whatever they're processing. Paste connection strings from the Redis and Databases tabs as environment variables, plus any external API tokens. Both Postgres and Redis use SSL/TLS for the connection.

4. Deploy

The worker starts and runs with restartPolicy: always. We don't run an HTTP health check — we monitor the process. If it exits, we restart it. If it crashes 5 times in 5 minutes, we mark the service failed and stop restarting until you intervene.

What you get

Workers built around how queue consumers actually run

Auto-restart with backoff

Container restart policy is always. Crashes are restarted with exponential backoff up to 30s. After 5 crashes in 5 minutes the service is marked failed — so a poison-pill message doesn't burn your CPU in a tight loop.

Graceful shutdown

On deploy or restart we send SIGTERM and wait up to 30 seconds (configurable up to 5 min) for the process to drain in-flight jobs. After the grace period, SIGKILL. This gives Sidekiq, BullMQ, and Celery enough time to finish whatever they were processing.

Real-time logs

Every line on stdout/stderr is streamed to the dashboard within ~200ms. Log lines are tagged with workspaceId, deploymentId, and requestId if your code emits one. Filter by level, search by substring, follow live.

Private networking

Workers, APIs, Postgres databases, and Redis caches all live under your workspace. Connection strings from the Databases and Redis tabs work from any service — paste once, use anywhere.

Resource limits per worker

Set memory and CPU caps per service from the dashboard, so a leaky worker doesn't take down your API on the same machine. Hit the cap and the process is OOM-killed and restarted — visible in logs as a clear OOM event, not a mystery 137 exit code.

Service slots, not replicas

Each worker is a single container by design. To run several workers in parallel, deploy the same repository as multiple worker services from the dashboard — they each count toward your plan's service limit (10 on Pro). Each pulls from your queue concurrently; the queue (Redis, RabbitMQ, SQS) handles distribution.

Common patterns

What people typically run as a worker

FAQ

Common questions

Worker vs on-demand script — which one do I want?

Worker = process that keeps running and waits for work to arrive (queue consumer, schedule loop). On-demand script = container that runs once and exits (migration, backup, monthly billing reconciliation). If your task takes <15 minutes and runs on a schedule or trigger, use a script. If it runs continuously, use a worker.

How do I run the same worker multiple times in parallel?

Deploy the same repository as multiple worker services (e.g. queue-worker-1, queue-worker-2) — each counts toward your plan's service limit. They all pull from your queue concurrently; the queue (Redis, RabbitMQ, SQS) handles the work distribution.

Does the worker get a public URL?

No. By design — workers don't speak HTTP to the public internet. If you need an HTTP-accessible worker (e.g., a status endpoint), use the API service type instead.

How do I see what my worker is doing right now?

The dashboard shows live logs streamed in real time. For application-level metrics (jobs processed, queue depth), instrument them in code and emit structured log lines — the dashboard search makes them easy to filter.

What if my worker writes to disk?

The container's filesystem is ephemeral — anything you write is lost on restart or redeploy. For persistent state, use a managed Postgres database or Redis cache, or attach an external object store (S3, R2, B2).

Run your queue consumer where your API lives.

Same workspace, same logs, same dashboard. From $35/mo on Pro.

Summary

Key takeaways

A worker on HostingGuru is a long-running background service with no public HTTP endpoint — the right shape for queue consumers, schedulers, websocket fan-out servers, and chat bots.

  • Workers restart automatically on a non-zero exit, with exponential back-off (1s, 2s, 4s … 60s).
  • Each worker counts as one service against your plan limit (Hobby: 3, Pro: 10).
  • Workers share env vars and the same git repo as your web service.
  • Restart loops are capped and surfaced in the dashboard so crash storms do not consume resources silently.

How is a worker different from an on-demand script?

An on-demand script runs once and exits — ideal for migrations or backfills. A worker is meant to stay running indefinitely, consuming messages or watching schedules. Pick a worker when the natural answer to "when does this stop?" is "never."

Which queue libraries work on HostingGuru workers?

BullMQ, Bee-Queue, Celery, RQ, Sidekiq, Oban, and any custom Redis or Postgres-based queue. Connect to the managed Redis URL injected as REDIS_URL, or to managed Postgres via DATABASE_URL.

Related docs