task_service
One-shot script with a timeout. Runs to completion (or kills on
timeout); does not stay alive. Sibling to process but
modeled as a condition = "completed" upstream rather than
"healthy".
Use this for migrations, fixture loaders, batch-prep steps that need to finish before app services start.
Manifest knobs
[services.migrate]
type = "task_service"
command = "python migrate.py"
cwd = "."
timeout_seconds = 300 # default; SIGTERM then SIGKILL
depends_on = [
{ service = "postgres", condition = "healthy" },
]
[services.api]
type = "process"
command = "python app.py"
depends_on = [
{ service = "migrate", condition = "completed" },
]
Lifecycle
- Spawns under the same env / lockfile rules as
process. - On clean exit (
exit 0): the orchestrator writes adonemarker into the per-service data dir; subsequent project opens skip the re-run unlessunibench start --freshor--seed. - On non-zero exit or timeout: marked Failed. Dependents that
declared
condition = "completed"get blocked (Failed, by the blocked-dependent rule).
Common gotchas
- Idempotency is yours. The orchestrator skips re-running a
successful task across project restarts. If your migration script
isn't safely re-runnable when
--freshstrips the done marker, you'll see the same problem you'd see in production. - Timeout vs slow CI. Default 300s is generous for local dev, tight for first-run model downloads. Bump per-task when you hit it.