feat: add graceful shutdown handler with signal trapping (#56)
Implement graceful shutdown handling for the async pipeline with proper signal trapping and cleanup coordination. Features: - GracefulShutdown class with SIGTERM/SIGINT signal trapping - Async event-based shutdown coordination - Configurable shutdown timeout (default: 30 seconds) - Cleanup callback registration (sync and async) - Force exit on second signal - Async context manager support - Platform-specific signal handling (Unix/Windows) Integration: - Updated __main__.py to use GracefulShutdown wrapper - Pipeline cleanup registered as shutdown callback - Proper logging of shutdown stages Tests: 25 new tests covering signal handling, timeouts, cleanup callbacks, and context manager behavior. Closes #56 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
29968897c5
commit
a18fc3493a
@@ -21,6 +21,7 @@ from pydantic import ValidationError
|
||||
from polymarket_insider_tracker import __version__
|
||||
from polymarket_insider_tracker.config import Settings, clear_settings_cache, get_settings
|
||||
from polymarket_insider_tracker.pipeline import Pipeline
|
||||
from polymarket_insider_tracker.shutdown import GracefulShutdown
|
||||
|
||||
# Application info
|
||||
APP_NAME = "Polymarket Insider Tracker"
|
||||
@@ -216,23 +217,41 @@ def run_config_check(settings: Settings) -> int:
|
||||
return EXIT_SUCCESS
|
||||
|
||||
|
||||
async def run_pipeline(settings: Settings, dry_run: bool) -> int:
|
||||
"""Run the main pipeline.
|
||||
async def run_pipeline(
|
||||
settings: Settings,
|
||||
dry_run: bool,
|
||||
shutdown_timeout: float = 30.0,
|
||||
) -> int:
|
||||
"""Run the main pipeline with graceful shutdown handling.
|
||||
|
||||
Args:
|
||||
settings: Application settings.
|
||||
dry_run: Whether to skip sending alerts.
|
||||
shutdown_timeout: Maximum time to wait for graceful shutdown.
|
||||
|
||||
Returns:
|
||||
Exit code.
|
||||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
shutdown = GracefulShutdown(timeout=shutdown_timeout)
|
||||
|
||||
try:
|
||||
pipeline = Pipeline(settings, dry_run=dry_run)
|
||||
async with shutdown:
|
||||
pipeline = Pipeline(settings, dry_run=dry_run)
|
||||
|
||||
logger.info("Starting pipeline...")
|
||||
await pipeline.run()
|
||||
# Register pipeline cleanup
|
||||
shutdown.register_cleanup(pipeline.stop)
|
||||
|
||||
logger.info("Starting pipeline...")
|
||||
await pipeline.start()
|
||||
|
||||
logger.info("Pipeline running. Press Ctrl+C to stop.")
|
||||
|
||||
# Wait for shutdown signal
|
||||
await shutdown.wait()
|
||||
|
||||
logger.info("Shutdown signal received, stopping pipeline...")
|
||||
await pipeline.stop()
|
||||
|
||||
return EXIT_SUCCESS
|
||||
except KeyboardInterrupt:
|
||||
|
||||
Reference in New Issue
Block a user