> ## Documentation Index
> Fetch the complete documentation index at: https://developer.upsun.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Work with workers

> Interact with your worker instances to handle background tasks for your apps.

Workers are instances of your code that aren't open to connections from other apps or services or the outside world.
They're good for handling background tasks.
See how to [configure a worker](https://developer.upsun.com/docs/configure-apps/image-properties/workers.md) for your app.

## Access the worker container

Like with any other application container,
Upsun Cloud allows you to connect to the worker instance through SSH to inspect logs and interact with it.

Use the `--worker` switch in the Upsun Cloud CLI, like so:

```bash theme={null}
upsun ssh --worker=queue
```

## Stopping a worker

If a worker instance needs to be updated during a new deployment,
a `SIGTERM` signal is first sent to the worker process to allow it to shut down gracefully.
If your worker process can't be interrupted mid-task, make sure it reacts to `SIGTERM` to pause its work gracefully.

If the process is still running after 15 seconds, a `SIGKILL` message is sent that force-terminates the worker process,
allowing the container to be shut down and restarted.

To restart a worker manually, [access the container](#access-the-worker-container) and run the following commands:

```bash theme={null}
sv stop app
sv start app
```

## Workers vs cron jobs

Worker instances don't run cron jobs.
Instead, both worker instances and cron tasks address similar use cases.
They both address out-of-band work that an application needs to do
but that shouldn't or can't be done as part of a normal web request.
They do so in different ways and so are fit for different use cases.

A cron job is well suited for tasks when:

* They need to happen on a fixed schedule, not continually.
* The task itself isn't especially long, as a running cron job blocks a new deployment.
* It's long but can be divided into many small queued tasks.
* A delay between when a task is registered and when it actually happens is acceptable.

A dedicated worker instance is a better fit if:

* Tasks should happen "now", but not block a web request.
* Tasks are large enough that they risk blocking a deploy, even if they're subdivided.
* The task in question is a continually running process rather than a stream of discrete units of work.

The appropriateness of one approach over the other also varies by language;
single-threaded languages would benefit more from either cron or workers than a language with native multi-threading, for instance.
If a given task seems like it would run equally well as a worker or as a cron,
cron is generally more efficient as it doesn't require its own container.

## Commands

The `commands` key defines the command to launch the worker application.
For now there is only a single command, `start`, but more will be added in the future.
The `commands.start` property is required.

The `start` key specifies the command to use to launch your worker application.
It may be any valid shell command, although most often it runs a command in your application in the language of your application.
If the command specified by the `start` key terminates, it's restarted automatically.

Note that [`deploy` and `post_deploy` hooks](https://developer.upsun.com/docs/configure-apps/hooks) as well as [`cron` commands](https://developer.upsun.com/docs/configure-apps/image-properties/crons)
run only on the [`web`](https://developer.upsun.com/docs/configure-apps/image-properties/web) container, not on workers.

## Inheritance

Workers inherit and can override several primary application properties, including `access`, `authorizations`, `mounts`, and `relationships`.
For a complete list, refer to the **Set in instance** column of the **Primary application properties** table
in the [single-runtime](https://developer.upsun.com/docs/configure-apps/app-reference/single-runtime-image.md#primary-application-properties)
and [composable image](https://developer.upsun.com/docs/configure-apps/app-reference/composable-image.md#primary-application-properties) topics.

Likewise [resources defined for the application container](https://developer.upsun.com/docs/manage-resources.md) are inherited by every worker, unless overridden explicitly.

That means, for example, that the following two `.upsun/config.yaml` definitions produce identical workers.


&#x20;   applications:
&#x20;     myapp: #The name of the app, which must be unique within the project.
&#x20;       type: python:\{\{version:python:latest}}
&#x20;       mounts:
&#x20;         test:
&#x20;           source: storage
&#x20;           source\_path: test
&#x20;       relationships:
&#x20;         mysql:
&#x20;       workers:
&#x20;         queue:
&#x20;           commands:
&#x20;             start: |
&#x20;               python queue-worker.py
&#x20;         mail:
&#x20;           commands:
&#x20;             start: |
&#x20;               python mail-worker.py
&#x20;   services:
&#x20;     mysql:
&#x20;       type: mariadb:\{\{version:mariadb:latest}}


&#x20;   applications:
&#x20;     myapp: #The name of the app, which must be unique within the project.
&#x20;       type: python:\{\{version:python:latest}}
&#x20;       workers:
&#x20;         queue:
&#x20;             commands:
&#x20;               start: |
&#x20;                 python queue-worker.py
&#x20;             mounts:
&#x20;               test:
&#x20;                 source: storage
&#x20;                 source\_path: test
&#x20;             mysql:
&#x20;         mail:
&#x20;           commands:
&#x20;             start: |
&#x20;               python mail-worker.py
&#x20;           mounts:
&#x20;             test:
&#x20;               source: storage
&#x20;               source\_path: test
&#x20;           mysql:
&#x20;   services:
&#x20;     mysql:
&#x20;       type: mariadb:\{\{version:mariadb:latest}}

In both cases, there are two worker instances named `queue` and `mail`.
Both have access to a MySQL/MariaDB service defined in `.upsun/config.yaml`,
through a [relationship](https://developer.upsun.com/docs/configure-apps/image-properties/relationships.md) that is identical to the *name* of that service (`mysql`).
Both also have their own separate [`storage` mount](https://developer.upsun.com/docs/configure-apps/image-properties/mounts).

## Customizing a worker

The most common properties to set in a worker to override the top-level settings are `variables` and its resources.
`variables` lets you instruct the application to run differently as a worker than as a web site,
whereas you can allocate [fewer worker-specific resources](https://developer.upsun.com/docs/manage-resources.md) for a container that is running only a single background process
(unlike the web site which is handling many requests at once).

For example, consider the following configuration:

&#x20;applications:
&#x20; \<APP\_NAME>: #The name of the app, which must be unique within the project.
&#x20;   type: "python:\{\{version:python:latest}}"
&#x20;   hooks:
&#x20;     build: |
&#x20;       pip install -r requirements.txt
&#x20;       pip install -e .
&#x20;       pip install gunicorn
&#x20;   relationships:
&#x20;     mysql:
&#x20;     rabbitmq:
&#x20;   variables:
&#x20;     env:
&#x20;         type: 'none'
&#x20;   web:
&#x20;     commands:
&#x20;       start: "gunicorn -b \$PORT project.wsgi:application"
&#x20;     variables:
&#x20;       env:
&#x20;         type: 'web'
&#x20;     mounts:
&#x20;       uploads:
&#x20;         source: storage
&#x20;         source\_path: uploads
&#x20;     locations:
&#x20;       "/":
&#x20;         root: ""
&#x20;         passthru: true
&#x20;         allow: false
&#x20;       "/static":
&#x20;         root: "static/"
&#x20;         allow: true
&#x20;   workers:
&#x20;     queue:
&#x20;       commands:
&#x20;         start: |
&#x20;           python queue-worker.py
&#x20;       variables:
&#x20;         env:
&#x20;           type: 'worker'
&#x20;       mounts:
&#x20;         scratch:
&#x20;           source: storage
&#x20;           source\_path: scratch
&#x20;     mail:
&#x20;       commands:
&#x20;         start: |
&#x20;           python mail-worker.py
&#x20;       variables:
&#x20;         env:
&#x20;           type: 'worker'
&#x20;       mounts: \{}
&#x20;       relationships:
&#x20;         rabbitmq:
&#x20; services:
&#x20; mysql:
&#x20;   type: 'mariadb:\{\{version:mariadb:latest}}'
&#x20; rabbitmq:
&#x20;   type: 'rabbitmq:\{\{version:rabbitmq:latest}}'
&#x20;&#x20;

There's a lot going on here, but it's all reasonably straightforward.
The configuration in `.upsun/config.yaml` takes a single Python 3.14 code base from your repository,
downloads all dependencies in `requirements.txt`, and then installs Gunicorn.
That artifact (your code plus the downloaded dependencies) is deployed as three separate container instances, all running Python 3.14.

The `web` instance starts a Gunicorn process to serve a web application.

* It runs the Gunicorn process to serve web requests, defined by the `project/wsgi.py` file which contains an `application` definition.
* It has an environment variable named `TYPE` with value `web`.
* It has a writable mount at `/app/uploads`.
* It has access to both a MySQL database and a RabbitMQ server, both of which are defined in `.upsun/config.yaml`.

The `queue` instance is a worker that isn't web-accessible.

* It runs the `queue-worker.py` script, and restart it automatically if it ever terminates.
* It has an environment variable named `TYPE` with value `worker`.
* It has a writable mount at `/app/scratch`.
* It has access to both a MySQL database and a RabbitMQ server,
  both of which are defined in `.upsun/config.yaml` (because it doesn't specify otherwise).

The `mail` instance is a worker that isn't web-accessible.

* It runs the `mail-worker.py` script, and restart it automatically if it ever terminates.
* It has an environment variable named `TYPE` with value `worker`.
* It has no writable file mounts at all.
* It has access only to the RabbitMQ server, through a different relationship name than on the `web` instance.
  It has no access to MySQL.

> [!NOTE]
>
> Upsun Cloud automatically allocates [default resources](https://developer.upsun.com/docs/manage-resources/resource-init.md) to each instance,
> unless you [define a different resource initialization strategy](https://developer.upsun.com/docs/manage-resources/resource-init.md#specify-a-resource-initialization-strategy).
> You can also [adjust resources](https://developer.upsun.com/docs/manage-resources/adjust-resources.md) after your project has been deployed.

For example, if you want the `web` instance to have a large upload space
and the `queue` instance to have a small amount of scratch space for temporary files,
you can allocate more CPU and RAM to the `web` instance than to the `queue` instance.

The `mail` instance has no persistent writable disk space at all, as it doesn't need it.
The `mail` instance also doesn't need any access to the SQL database, so for security reasons it has none.

Each instance can also check the `TYPE` environment variable to detect how it's running
and, if appropriate, adjust its behavior accordingly.

## Mounts

When defining a [worker](https://developer.upsun.com/docs/configure-apps/image-properties/workers.md) instance,
keep in mind what mount behavior you want.

`tmp` and `instance` local mounts are a separate storage area for each instance,
while `storage` mounts can be shared between instances.

For example, you can define a `storage` mount (called `shared_dir`) to be used by a `web` instance,
and a `tmp` mount (called `local_dir`) to be used by a `queue` worker instance:


&#x20;   applications:
&#x20;     myapp: #The name of the app, which must be unique within the project.
&#x20;       type: "nodejs:\{\{version:nodejs:latest}}"

&#x20;       \# Define a web instance
&#x20;       web:
&#x20;         locations:
&#x20;           "/":
&#x20;             root: "public"
&#x20;             passthru: true
&#x20;             index: \['index.html']

&#x20;       mounts:
&#x20;         \# Define a storage mount that's available to both instances together
&#x20;         'shared\_dir':
&#x20;           source: storage
&#x20;           service: files
&#x20;           source\_path: our\_stuff

&#x20;         \# Define a local mount that's available to each instance separately
&#x20;         'local\_dir':
&#x20;           source: tmp
&#x20;           source\_path: my\_stuff

&#x20;       \# Define a worker instance from the same code but with a different start
&#x20;       workers:
&#x20;         queue:
&#x20;           commands:
&#x20;             start: ./start.sh

Both the `web` instance and `queue` worker have their own, dedicated `local_dir` mount.
Note that:

* Each `local_dir` mount is a [`tmp` mount](https://developer.upsun.com/docs/configure-apps/image-properties/mounts) with a **maximum allocation of 8 GB**.\

* `tmp` mounts **may be removed** during infrastructure maintenance operations.

Both the `web` instance and `queue` worker also have a `shared_dir` mount pointing to the same network storage space.
They can both read and write to it simultaneously.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.