Migrating production infrastructure? Get up to ₹10,000 in migration credits. Apply now
voroaDocs
Compute

Deploy a background worker: queues and consumers

Run a long-running background worker from GitHub on Voroa — queues, consumers and processors with no web port. Hosted in India, billed in INR with GST.

A background worker is a long-running process with no web port — a queue consumer, a message processor, a scheduler, or any job that runs continuously in the background. On Voroa you deploy a worker straight from a GitHub repository, and it stays running around the clock.

Worker vs web service

A web service listens on a port and serves HTTP requests — it has a URL. A worker does not: it has no web address and answers no HTTP requests. It just runs your process continuously.

Use a worker when your code needs to run in the background — for example consuming jobs from a queue, processing a stream, or polling an external system — rather than responding to web requests.

What you need

  • A GitHub repository connected to Voroa.
  • A start command — the command that launches your long-running process, for example node worker.js, python worker.py, or npm run worker. A worker has no web server to detect automatically, so the start command is required. If you build from your own Dockerfile, the start command is optional - the CMD in your Dockerfile runs instead.

Deploy a worker

  1. From your dashboard choose New and select Background Worker.
  2. Pick your repository and branch.
  3. Set the Root directory if your worker lives in a subfolder of the repository (leave it as / for the repository root). The value is case-sensitive, so Src and src are different folders - type it exactly as it appears in your repository.
  4. Enter your Start command (Automatic build method only).
  5. Under Runtime, pick a Build method. Automatic detects your language and builds it for you. Dockerfile builds from your own Dockerfile - choose it when your worker needs system packages or a specific base image, and set the Dockerfile path relative to the root directory (/Dockerfile by default).
  6. Choose an instance for the worker’s memory and CPU. See the sizes below.
  7. Create. Voroa builds your code and starts the worker.

Worker instances and what they cost

A worker runs continuously, so unlike a web service it is never idle-stopped and its memory is held for you around the clock. You pick the instance when you create the worker, and you can move to a different one later from the worker’s own plan page.

A background worker costs exactly the same as a web service of the same size. It is the same instance list on both, rung for rung - same memory, same CPU, same price - so you never have to work out which of the two is cheaper for the work you are running. The live prices are on the create page and on the pricing page, and they are deliberately not repeated here: a price written in two places eventually disagrees with itself.

There is a free instance, and it is the same free instance a web service gets. A free worker shares the workspace’s monthly free hours with the other free services - see Free instances.

Prices exclude GST, which is added on your invoice. A paid instance bills monthly, and your first charge is prorated to your billing date - the exact amount is shown on the payment screen before you pay, so nothing is charged that you have not seen first.

Most workers are comfortable on the free instance: a queue consumer that spends its time waiting usually holds well under 100 MB. Start there. If your worker runs out of memory you will see it restart, and the worker’s Metrics tab shows what it is actually using - move up only when that number tells you to, not in advance.

Seeing how big your image is

Every deploy that builds an image measures it, and the size appears on your service’s Overview as Image size. It is the size of the image this deploy produced - not a sum of the older versions Voroa keeps for one-click rollback, which are our storage and not yours.

If it reads as a dash, nothing has been measured yet: either the service has not deployed since this became available, or it is a static site, which has no image at all.

Image size limits

Each instance size allows an image up to a limit, and a build that produces a larger one is refused.

Instance Image limit
Free 8 GB
Starter 12 GB
Standard 16 GB
Pro 24 GB
Pro Plus 32 GB

The limit is generous on purpose - most workers are nowhere near it. If you do hit it, the build log tells you the size we measured and the limit it passed, and your running worker is not changed. The new version simply does not go live, so there is no downtime while you sort it out.

Making your image smaller

Check for a double install first. This is the most common cause by far, and usually the whole problem. If your repository has a requirements.txt (or a package.json) AND your service also has a Build Command that installs dependencies, then everything is being installed twice. (One exception: a Python install in a repository that also has a package.json is not a duplicate - that repository is built as Node.js, so nothing was installed from requirements.txt in the first place.) Both copies stay in the image permanently - removing files in a later build step does not free the space an earlier step used.

You do not have to work this out yourself: when it happens, your build log says so. Look for a line starting “Your dependencies are being installed twice”. Your build still succeeds - it is a note, not an error.

Pick one and remove the other. Either keep requirements.txt and drop the install from your Build Command, or keep the Build Command and remove requirements.txt. An image built this way is often three to five times smaller, and the build finishes much faster too.

Two smaller things worth checking:

  • Install only what you run. Development and testing packages do not need to be in the image that runs in production.
  • Pick the lighter build of a heavy package. Machine-learning libraries in particular ship a GPU-enabled build by default that can be several gigabytes; the CPU-only build is a fraction of the size and is what a worker without a GPU actually uses.

If none of that helps, move to a larger instance - each size allows a larger image.

How Voroa knows your worker is healthy

A worker has no web port to check, so Voroa confirms it is running from the process state itself. After the build finishes, your worker shows Starting, then Live once its process has stayed up for a full minute. That wait is deliberate. A worker that dies after ten seconds looks exactly like a healthy one for the first few seconds, so Voroa waits long enough for the difference to show rather than calling it Live and being wrong. If the process exits or starts looping in that time, the deploy is marked Failed to start instead of a false success.

Voroa also keeps watching after the deploy is over. If your worker starts stopping and restarting again and again, we email the person the service belongs to, so you find out even if nobody is looking at the dashboard. You get one email per problem, not one per restart.

When a worker keeps restarting

A worker is expected to keep running. If it stops, Voroa starts it again — which means a worker that does not stay up will restart forever. Three causes account for almost all of it:

  • The start command cannot run. It has to be a command that works inside your project, such as node worker.js or python worker.py. Commands meant for your own machine will not work.
  • Something the code needs is not installed. If your program downloads or installs anything before it can run — a browser for a scraping library, for example — that step has to happen during the build, not at start-up.
  • The program finishes instead of staying running. A script that does its work and ends will be started again immediately. A worker has to keep running, usually by waiting on a queue, a timer or an event loop.

Open your worker’s Logs and read the last lines before it stops. That is where the reason is.

Reading process output

Print progress and errors to standard output. You can follow your worker’s output in its Logs, the same way you would for a web service.

Environment variables

Set any configuration your worker needs — API keys, queue URLs, database connection strings — as environment variables on the worker. You can add them when you create the worker or any time afterward from its Environment tab. Values are stored securely and injected at runtime; Voroa keeps only the variable names for display, never the values. Mark a variable as available at build time if your build needs it. (PORT is managed by the platform and cannot be set.)

Use a custom Dockerfile

By default Voroa detects your language and builds your worker automatically. If your job needs specific system tooling — a database client, a cloud CLI, image libraries, or anything else — choose the Docker runtime and Voroa builds your worker from the Dockerfile in your repository. Install whatever your job needs in the Dockerfile, and it will be available when your worker runs.

If your Dockerfile is not at the repository root, set the Dockerfile path (for example /docker/Dockerfile). With the Docker runtime the start command is optional — your image’s CMD runs unless you override it.

Running a scheduled job inside a worker

If you need a command to run on a schedule rather than continuously, add a Scheduled Task to your worker — see the guide on scheduling a task. The task runs inside your worker’s running container on the schedule you set.

All Voroa services run in Mumbai (IN), and your usage is billed in INR with a GST invoice.

For what a worker includes and what each size costs, see background workers.

Last updated November 12, 2026