patternpythonMajorpending
Pattern: Graceful shutdown for long-running services
Viewed 0 times
graceful-shutdownSIGTERMdrainin-flightzero-downtime
Problem
Killing a service abruptly can leave requests half-processed, database transactions incomplete, or downstream services in an inconsistent state.
Solution
Implement graceful shutdown that finishes in-flight work:
import signal, asyncio, sys
class GracefulServer:
def __init__(self):
self.shutting_down = False
self.active_requests = 0
def setup_signal_handlers(self):
for sig in (signal.SIGTERM, signal.SIGINT):
signal.signal(sig, self._handle_signal)
def _handle_signal(self, signum, frame):
print(f'Received signal {signum}, shutting down gracefully...')
self.shutting_down = True
self._begin_shutdown()
def _begin_shutdown(self):
# 1. Stop accepting new connections
self.server.close()
# 2. Remove from load balancer (health check returns 503)
# 3. Wait for in-flight requests (with timeout)
deadline = time.time() + 30 # 30 second grace period
while self.active_requests > 0 and time.time() < deadline:
time.sleep(0.5)
# 4. Close database connections
self.db_pool.close()
# 5. Flush logs and metrics
self.logger.flush()
# 6. Exit
sys.exit(0)
# Kubernetes: set terminationGracePeriodSeconds
# Docker: STOPSIGNAL SIGTERM in Dockerfile
# Pre-stop hook for load balancer deregistration:
# lifecycle:
# preStop:
# command: ["sleep", "5"] # Wait for LB to drain
import signal, asyncio, sys
class GracefulServer:
def __init__(self):
self.shutting_down = False
self.active_requests = 0
def setup_signal_handlers(self):
for sig in (signal.SIGTERM, signal.SIGINT):
signal.signal(sig, self._handle_signal)
def _handle_signal(self, signum, frame):
print(f'Received signal {signum}, shutting down gracefully...')
self.shutting_down = True
self._begin_shutdown()
def _begin_shutdown(self):
# 1. Stop accepting new connections
self.server.close()
# 2. Remove from load balancer (health check returns 503)
# 3. Wait for in-flight requests (with timeout)
deadline = time.time() + 30 # 30 second grace period
while self.active_requests > 0 and time.time() < deadline:
time.sleep(0.5)
# 4. Close database connections
self.db_pool.close()
# 5. Flush logs and metrics
self.logger.flush()
# 6. Exit
sys.exit(0)
# Kubernetes: set terminationGracePeriodSeconds
# Docker: STOPSIGNAL SIGTERM in Dockerfile
# Pre-stop hook for load balancer deregistration:
# lifecycle:
# preStop:
# command: ["sleep", "5"] # Wait for LB to drain
Why
Graceful shutdown prevents data loss, ensures consistency, and allows zero-downtime deployments by finishing work before stopping.
Revisions (0)
No revisions yet.