Skip to content

Deployment

The shape of a worker

gylo worker --app myapp:app --queue default,mail

One gylo process is a Rust supervisor that owns the database pool, leasing, retries, scheduling, and every state write. It spawns one Python child per core (--processes) and dispatches jobs to them over a Unix socket. Task code holds the interpreter lock, so a single child uses a single core no matter how high concurrency goes — the per-core children are what spend the rest of the machine. Scale beyond one machine by running more workers; they coordinate through the queue itself and need no discovery of each other.

A child that dies is restarted with backoff and its in-flight jobs handed back; a child that cannot stay up (usually a misconfigured --app) stops the worker with the child's own last words in the error, rather than leaving a process that looks healthy at zero capacity.

Settings that matter

Flag Default What it truly controls
--processes core count parallelism; one child ≈ one core
--concurrency 256 in-flight jobs per child; how far ahead of it the supervisor leases
--batch 128 jobs leased per round trip — bounded for crash-recovery latency, not speed
--lease 30s how long a dead worker's jobs wait before another recovers them
--retry-base 1s delay before the first retry; doubles each attempt, with jitter
--retry-cap 1h ceiling the retry backoff never exceeds
--retain-completed 24h finished-job (and result) lifetime — see below
--retain-discarded 7d dead-letter lifetime

Leases renew automatically while a job runs, so --lease bounds recovery time, never task duration. Settings whose failure mode would be silent are rejected at startup instead — a maintenance interval at or above the lease, for instance, would reclaim healthy jobs and run them twice.

Queues: --queue a,b,c consumes several; priority compares across them, so a high-priority job in a quiet queue is not outranked by a busy neighbour.

Shutdown

SIGTERM and SIGINT both drain: stop leasing, finish in-flight work (up to 30s), exit 0. Handlers are installed before anything else at startup, so a rollout's early SIGTERM is honoured too. Anything not drained in time is recovered by lease expiry — kill -9 is an ordinary, tested event, not a disaster.

For Kubernetes: terminationGracePeriodSeconds ≥ 40, and use --observe :9464 for probes — liveness on /healthz (process alive), never on database reachability: a probe that fails on a Postgres blip restarts every worker at once, turning a recovery into an outage.

The table stays bounded

Maintenance deletes completed jobs after --retain-completed and dead letters after --retain-discarded, in bounded, time-boxed batches that never delay crash recovery. Two consequences worth planning around: the completed window is also how long results are retrievable, and deleted space is reused rather than returned to the OS — the table plateaus, it does not shrink. First deployment onto a database with months of history: gylo jobs prune --older-than 30d once, deliberately, rather than letting maintenance discover it.

Migrations

gylo migrate before rollout — embedded in the binary, additive, safe to re-run, and safe to run while old workers are still up.