Disposability
Processes start in seconds and shut down cleanly when asked, so the platform can replace them at any moment.
Maximize robustness with fast startup and graceful shutdown. A twelve-factor process can be started or stopped at a moment's notice. Platforms do this all the time: to deploy a new release, to scale down at night, or to move work off a failing machine.
That asks two things of every process:
- Start fast. A few seconds, ideally. Slow startup makes deploys and scaling sluggish, and leaves you short of capacity while a crashed process comes back.
- Stop gracefully. When asked to stop, finish what you're doing, then exit.
#How a stop works
Platforms stop a process in two steps. First a polite SIGTERM, then, if it hasn't exited after a grace period, a SIGKILL that can't be caught.
1.SIGTERM
Docker sends SIGTERM and starts a 10-second timer.
#Handle SIGTERM
Production servers like Gunicorn and Uvicorn already drain requests on SIGTERM. For a worker loop you wrote yourself, catch the signal and finish the current job:
import signal
import sys
running = True
def stop(signum, frame):
global running
running = False # finish the current job, then leave the loop
signal.signal(signal.SIGTERM, stop)
while running:
job = queue.get(timeout=1)
if job:
handle(job)
sys.exit(0)$ docker stop shop-worker
# SIGTERM sent; the worker finishes its job
shop-worker
$ docker inspect -f '{{.State.ExitCode}}' shop-worker
0#Be ready for a crash, too
Graceful shutdown is the polite case. Machines also lose power. Make jobs safe to run twice, and put a job back on the queue if a worker dies holding it, so a crash delays work instead of losing it.
In Kubernetes, the same SIGTERM and grace period apply when a pod is deleted, and terminationGracePeriodSeconds sets the timer. Delete a pod in the Kubernetes lab and watch a replacement take its place.
Referenced by