Short answer: drain the thing that feeds the worker, not the worker itself.
Assuming Prefect 3.x, here’s a practical runbook for blue/green or maintenance when using process or docker workers on the same machine.
Two viable patterns
A) Single pool/queue (simple drain/restart)
- Stop the old worker from taking new work:
- Pause the work pool: prefect work-pool pause <pool>
Docs:
https://docs-3.prefect.io/v3/concepts/work-pools
CLI help: prefect work-pool pause --help
- Alternatively, pause just the work queue(s) the worker polls: prefect work-queue pause <queue> --pool <pool>
CLI help: prefect work-queue pause --help
- Or set pool (or queue) concurrency to 0 to allow current runs to finish but start no new ones:
- Pool: prefect work-pool set-concurrency-limit <pool> 0
CLI help: prefect work-pool set-concurrency-limit --help
- Queue: prefect work-queue set-concurrency-limit <queue> --pool <pool> 0
- Wait for existing runs to finish:
- Inspect the pool/queue: prefect work-pool inspect <pool> or prefect work-queue inspect <queue> --pool <pool>
CLI help: prefect work-pool inspect --help, prefect work-queue inspect --help
- Or list running flow runs: prefect flow-run ls --state RUNNING
CLI help: prefect flow-run ls --help
- In the UI, filter by Work Pool and state=Running; wait until zero.
- Stop the old worker service (systemd, Docker, whatever you’re using).
- Start the new worker (same pool/queue):
- prefect worker start --pool <pool> [--work-queue <queue> ...]
CLI help: prefect worker start --help
- Resume the pool/queue if you paused it:
- Pool: prefect work-pool resume <pool>
- Queue: prefect work-queue resume <queue> --pool <pool>
B) True blue/green (no contention, old only finishes existing)
- Create a “green” destination (new pool or new queue):
- New pool: prefect work-pool create <green-pool> --type <process|docker>
- Or a new queue in the same pool: prefect work-queue create <green-queue> --pool <pool>
- Start new workers pointing at the green pool/queue.
- Update deployments to target the green pool/queue so all new flow runs route to green. Existing scheduled runs already enqueued to “blue” will stay there.
- Pause the “blue” pool/queue (or set its concurrency to 0) so it stops taking more work; the blue workers will only finish what they already claimed.
- Once blue shows no running flow runs, stop the blue workers and delete the old pool/queue when you’re ready.
Notes by worker type
- Process workers (local subprocesses):
- If you terminate the worker process while a run is still executing, you risk interrupting the child process and crashing the flow. If you care about the run, drain first; don’t kill the worker until the pool/queue shows zero RUNNING.
- There is no “prefect worker drain” or worker-level pause; you drain via the pool/queue.
- Docker workers (containers per run):
- Flows run in separate containers; those containers typically keep running even if the worker process exits. Still, the safest path is the same: pause/drain, then stop the old worker.
- Docker how-to overview:
https://docs-3.prefect.io/v3/how-to-guides/deployment_infra/docker
Operational tips
- Pause vs concurrency=0:
- Both prevent new runs from starting. Setting concurrency to 0 is a soft drain; pause is a hard stop. Either is fine; pause is explicit.
- Race window:
- A worker may have just claimed a run right before you pause. Give it a few seconds, then re-check “Running” before pulling the plug.
- Monitoring drain:
- CLI: prefect work-pool inspect <pool>, prefect work-queue inspect <queue> --pool <pool>, and prefect flow-run ls --state RUNNING
- UI: filter by work pool/queue and state=Running.