Skip to content
sitesolide

Docs Guides

Workers and scheduled jobs

Under the manifest's services key, a project runs processes that answer no request: a worker that runs for good, or a job at set times.

Each entry names a service and takes a start. What else it declares sets its kind:

KindDeclaresRuns
Serverportfor good, listening on its port
Worker"internal": true, no portfor good, listening on nothing
Scheduledscheduleat the times it names, each run to its end

A worker or a scheduled service goes under services even alone: a top-level start is always a server.

In sitesolide.json, a page, a worker and a job every quarter of an hour:

{
  "slug": "background",
  "services": {
    "web": { "start": "/usr/local/bin/bun run web.ts", "port": 3041 },
    "worker": { "start": "/usr/local/bin/bun run worker.ts", "internal": true },
    "tally": { "start": "/usr/local/bin/bun run tally.ts", "schedule": "*:0/15", "timeout": "1m" }
  }
}

The repository's background example deploys as it is.

A worker suits a queue's consumer, a bot holding a connection, or an agent.

  • It comes back. systemd restarts it 2 seconds after a failure, then waits longer each time, up to 5 minutes.
  • It yields. When they compete for the processor, a site gets five times a worker's share.
  • It stops on SIGTERM. At a deploy or a restart, systemd sends SIGTERM, and kills it if it still runs 90 seconds later. Finish the current step and exit.

schedule takes a systemd calendar expression:

scheduleRuns
dailyevery day at midnight
*:0/15every quarter of an hour
Mon..Fri 08:00on weekdays at eight in the morning
*-*-* 06:30 Europe/Parisevery day at 6:30, Paris time

Times are the server's, UTC on most cloud images, unless the expression names a time zone. timeout stops a run that hangs: 90s, 15m, 2h, an hour by default and a day at most. A schedule systemd cannot read stops deploy before it writes anything.

  • A deploy runs nothing: the first run comes at the next scheduled time.
  • A time that comes during a run is skipped: runs never overlap.
  • A failed run is not retried before its next time.
  • A time missed while the server was down runs once, when it is back.

A project whose services are all workers or scheduled jobs, with no publicDir, serves no page. Its address answers 200 with a line saying so, and it cannot have its own domain.

{
  "slug": "nightly",
  "services": {
    "sync": { "start": "/usr/local/bin/bun run sync.ts", "schedule": "daily" }
  }
}

sitesolide status shows each scheduled service's last run, how it ended, and its next run. sitesolide logs shows every run beside the project's other services.

sitesolide status

A background service shares the server with every site, and can slow them down. Light work fits, such as waiting on an outside API. These do not:

  • A headless browser. The unit's confinement refuses Chromium's sandbox.
  • Heavy computing, such as video encoding or a model run on the processor.
  • Mass email from the server's address. Blocklists would hit every site: call a mail provider's API instead.