Run background processes·续
src/index.tsts
export class MyContainer extends DurableObject<Env> {
// ...
async alarm(): Promise<void> {
let running = false;
for (const [key, argv] of await this.ctx.storage.list<string[]>({
prefix: "process:",
})) {
const id = key.slice("process:".length);
const status = await this.status(id);
if (status?.state === "running" || status?.state === "starting") {
running = true;
} else {
console.log({ event: "process.ended", id, argv, status });
await this.ctx.storage.delete(key);
}
}
if (running) {
await this.ctx.storage.setAlarm(Date.now() + 60_000);
}
}
}
```
A running process does not keep the container running. The alarm checks every process each minute, and each alarm keeps the container running. A Durable Object that restarted between alarms sets the 10-minute inactivity timeout again in its constructor. The container stops 10 minutes after the alarm finds that the last process has ended. For more information, refer to [Sandbox lifetime](https://developers.cloudflare.com/sandbox/concepts/lifetime/#activity-keeps-an-instance-running).
A Durable Object has one alarm. If your class already has an `alarm()` handler, merge the process checks into it, and set the alarm to the earliest time that any check needs. For more information, refer to [Alarms](https://developers.cloudflare.com/durable-objects/api/alarms/).
When a process ends, the alarm writes a `process.ended` log to [Workers Logs](https://developers.cloudflare.com/workers/observability/logs/workers-logs/) within a minute. Replace the `console.log()` call with what your application does next, such as sending a notification.
7. Add routes to your Worker that call these methods:
*src/index.jsjs*
```js
const command = [
"sh",
"-c",
"echo ready; for i in $(seq 1 300); do echo tick $i; sleep 1; done",
];
export default {
async fetch(request, env) {
const url = new URL(request.url);
const match = /^\/processes\/([a-z0-9-]{1,63})(\/logs)?$/.exec(
url.pathname,
);
if (!match) {
return new Response("Not found", { status: 404 });
}
const [, id, logs] = match;
const sandbox = env.MY_CONTAINER.getByName("sandbox");
if (logs) {
const stream =
url.searchParams.get("stream") === "stderr" ? "stderr" : "stdout";
const output = await sandbox.logs(id, stream);
return output === undefined
? new Response("Not found", { status: 404 })
: new Response(output);
}
if (request.method === "POST") {
return (await sandbox.startProcess(id, command))
? new Response(null, { status: 201 })
: new Response("The process ID is in use", { status: 409 });
}
if (request.method === "DELETE") {
return (await sandbox.stop(id))
? new Response(null, { status: 202 })
: new Response("The process is not running", { status: 409 });
}
const status = await sandbox.status(id);
return status
? Response.json(status)
: new Response("Not found", { status: 404 });
},
};
```
*src/index.tsts*
```ts
const command = [
"sh",
"-c",
"echo ready; for i in $(seq 1 300); do echo tick $i; sleep 1; done",
];
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
const match = /^\/processes\/([a-z0-9-]{1,63})(\/logs)?$/.exec(
url.pathname,
);
if (!match) {
return new Response("Not found", { status: 404 });
}
const [, id, logs] = match;
const sandbox = env.MY_CONTAINER.getByName("sandbox");
if (logs) {
const stream =
url.searchParams.get("stream") === "stderr" ? "stderr" : "stdout";
const output = await sandbox.logs(id, stream);
return output === undefined
? new Response("Not found", { status: 404 })
: new Response(output);
}
if (request.method === "POST") {
return (await sandbox.startProcess(id, command))
? new Response(null, { status: 201 })
: new Response("The process ID is in use", { status: 409 });
}
if (request.method === "DELETE") {
return (await sandbox.stop(id))
? new Response(null, { status: 202 })
: new Response("The process is not running", { status: 409 });
}
const status = await sandbox.status(id);
return status
? Response.json(status)
: new Response("Not found", { status: 404 });
},
} satisfies ExportedHandler<Env>;
```
This example command prints `ready`, then prints a line each second for five minutes. Replace it with your own command. The route accepts only process IDs that are safe in a path, because each ID becomes a directory name.
8. Deploy your Worker:npmyarnpnpm
npx wrangler deploy ```
yarn wrangler deploy
```
pnpm wrangler deploy ```
- Start a process named
ticker, then check it. Replace the example hostname with theworkers.devURL that Wrangler prints:
curl https://<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev/processes/ticker --request POST
curl https://<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev/processes/ticker
```
The first request responds with `201`, and a second `POST` with the same ID responds with `409`. The status includes the process ID:
```json
{ "state": "running", "pid": 354 }
```
10. Read the output so far:
```sh
curl https://<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev/processes/ticker/logs
```
The request prints the lines so far and ends:
```txt
ready
tick 1
tick 2
tick 3
```
Add `stream=stderr` to the query to read standard error.
11. Stop the process, then check it again:
```sh
curl https://<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev/processes/ticker --request DELETE
curl https://<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev/processes/ticker
```
The `DELETE` request responds with `202`. The status shows the exit code:
```json
{ "state": "exited", "exitCode": 143 }
```
## Related resources
- [Follow a background process](https://developers.cloudflare.com/sandbox/commands/follow-a-background-process/): stream the output of a process while it runs, or wait until it prints a line.
- [Stream command output](https://developers.cloudflare.com/sandbox/commands/stream-command-output/): commands that finish while the request is open.
- [Run a server in the background](https://developers.cloudflare.com/sandbox/commands/run-a-server-in-the-background/): processes that run until the container stops.
- [Preview a web application](https://developers.cloudflare.com/sandbox/previews/): a web server as the main process.
- [Process workspace example ↗︎](https://github.com/cloudflare/sandbox-sdk/tree/main/examples/process-workspace): a deployable Worker that runs processes with the same approach, plus routes that list processes and wait for one to exit. Its scripts do not record the boot ID.
- [Sandbox lifetime](https://developers.cloudflare.com/sandbox/concepts/lifetime/)
- [Durable Object alarms](https://developers.cloudflare.com/durable-objects/api/alarms/)
Was this helpful?
YesNo
## On this page
[Docs](https://developers.cloudflare.com/)
```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/sandbox/commands/run-background-processes/#page","headline":"Run background processes","description":"Start a background process in a Linux sandbox, then check it, read its output, and stop it from later requests.","url":"https://developers.cloudflare.com/sandbox/commands/run-background-processes/","inLanguage":"en","image":"https://developers.cloudflare.com/sandbox/commands/run-background-processes/og.png?v=e231bc0f3fb59dce","dateModified":"2026-10-23","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
description: Run Python code in a Linux sandbox with the Python version and packages you choose, and return its output. title: Run Python code image: https://developers.cloudflare.com/sandbox/commands/run-python-code/og.png?v=bfa2c3a9669d3792
Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/sandbox/llms.txt
Use this file to discover all available pages before exploring further.
