How to Mock a SIGTERM Handler in Python
Create a graceful shutdown handler for SIGTERM and SIGINT signals, then test it by simulating a signal delivery without terminating the process.
Python code
31 linesimport signal
import time
class Service:
def __init__(self):
self.running = True
def shutdown(self, signum, frame):
print(f"Received signal {signum}, shutting down gracefully...")
self.running = False
def run(self):
signal.signal(signal.SIGTERM, self.shutdown)
signal.signal(signal.SIGINT, self.shutdown)
print("Service started, press Ctrl+C to stop")
while self.running:
time.sleep(0.5)
print("Service stopped")
def mock_signal(self, signum):
# Simulate receiving a signal without killing the process
self.shutdown(signum, None)
if __name__ == "__main__":
service = Service()
# Instead of running forever, simulate a SIGTERM after 1 second
import threading
timer = threading.Timer(1.0, service.mock_signal, args=[signal.SIGTERM])
timer.start()
service.run()
timer.join()
Output
Service started, press Ctrl+C to stop
Received signal 15, shutting down gracefully...
Service stopped
How it works
The signal.signal calls register the shutdown method as the handler for both SIGTERM (15) and SIGINT (2). The mock_signal method directly calls the same handler, simulating what happens when the OS delivers a signal. The threading.Timer fires after one second, exercising the shutdown path without actually killing the process. The main loop checks the running flag every 0.5 seconds, so it exits cleanly after the mock signal flips it to False. This pattern is critical for production services that must flush data or close resources before exiting.
Common mistakes
- Calling `signal.signal` inside the loop instead of once at startup
- Forgetting to pass both `signum` and `frame` arguments to the handler
- Using `sys.exit()` directly instead of setting a running flag
- Creating the timer without joining it, leaving threads dangling
Variations
- Use `signal.signal(signal.SIGTERM, lambda s, f: service.shutdown())` to wrap the handler
- Replace the Timer with `asyncio.get_event_loop().call_later(1, service.mock_signal, signal.SIGTERM)` for async services
Real-world use cases
- Web servers like Flask or Django that need to close database connections before pod termination.
- Kubernetes-managed containers that must respond to SIGTERM within a grace period.
- Data pipeline workers that must finish in-flight batch jobs before exiting.
Sponsored
More from Production deployment patterns
- Auto Rollback on Error Rate Exceeded in Python medium
- Automate Semantic Versioning with Conventional Commits in Python medium
- Design a Data Helper for Beginners in Python easy
- Docker healthcheck CMD mock in Python easy
- Generate a Mock Artifact Version Tag in Python easy
- Generate a docker-compose.yml with mock services in Python easy
Keep learning
Related tutorials and quizzes for this topic.