From 52ccca71614d7e146677772ca5b9e42d898623d2 Mon Sep 17 00:00:00 2001 From: "k.eaven" Date: Tue, 12 Aug 2025 03:52:40 -0700 Subject: [PATCH] Update system signal handling --- dockerfile | 3 --- entrypoint.sh | 11 +--------- pterodisbot.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/dockerfile b/dockerfile index e028cf3..cde5bd4 100644 --- a/dockerfile +++ b/dockerfile @@ -32,9 +32,6 @@ RUN mkdir -p logs && \ chown -R bot:bot embed && \ chmod -R 777 embed -# Make the entrypoint script executable -RUN chmod +x /app/entrypoint.sh - # Switch to non root user USER bot diff --git a/entrypoint.sh b/entrypoint.sh index 133d6ea..bf8aca0 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,13 +1,4 @@ #!/bin/sh # Run the application in the background -python generate_config.py && python pterodisbot.py & - -# Capture the process ID -PID=$! - -# Wait for SIGTERM signal -trap "kill -INT $PID" SIGTERM - -# Wait for the process to complete -wait $PID \ No newline at end of file +python generate_config.py && python pterodisbot.py \ No newline at end of file diff --git a/pterodisbot.py b/pterodisbot.py index d9ec9f0..87c09d8 100644 --- a/pterodisbot.py +++ b/pterodisbot.py @@ -17,6 +17,9 @@ import discord from discord.ext import commands, tasks from discord import app_commands import os +import sys +import signal +import types import aiohttp import asyncio import json @@ -923,7 +926,6 @@ class PterodactylBot(commands.Bot): if self.pterodactyl_api: await self.pterodactyl_api.close() await super().close() - logger.info("Bot shutting down") # ============================================== # DISCORD COMMANDS @@ -1089,17 +1091,66 @@ async def on_ready(): except Exception as e: logger.error(f"Command sync failed: {str(e)}") +# ============================================== +# SYSTEM SIGNAL HANDLERS +# ============================================== + +def handle_sigint(signum: int, frame: types.FrameType) -> None: + """ + Handle SIGINT signals (Ctrl+C) by initiating graceful shutdown. + + Args: + signum: The signal number (signal.SIGINT) + frame: Current stack frame (unused but required by signal handler signature) + """ + logger.info("Received SIGINT (Ctrl+C), initiating graceful shutdown...") + raise KeyboardInterrupt + +def handle_sigterm(signum: int, frame: types.FrameType) -> None: + """ + Handle SIGTERM signals (container stop) by initiating graceful shutdown. + + Args: + signum: The signal number (signal.SIGTERM) + frame: Current stack frame (unused but required by signal handler signature) + """ + logger.info("Received SIGTERM (container stop), initiating graceful shutdown...") + raise KeyboardInterrupt + # ============================================== # BOT STARTUP # ============================================== if __name__ == "__main__": + """ + Main entry point for the bot application. + + Handles: + - Signal registration for graceful shutdowns (SIGINT/SIGTERM) + - Primary bot execution loop + - Error handling and crash reporting + - Resource cleanup on shutdown + + Flow: + 1. Initialize signal handlers + 2. Start bot with Discord token + 3. Handle interrupts and exceptions + 4. Execute final cleanup + """ logger.info("Starting bot initialization") + + # Register signal handlers + signal.signal(signal.SIGINT, handle_sigint) # For Ctrl+C + signal.signal(signal.SIGTERM, handle_sigterm) # For container stop commands + logger.info("System signal handlers registered") + try: bot.run(DISCORD_TOKEN) except KeyboardInterrupt: - logger.info("Bot shutting down due to keyboard interrupt") + logger.info("Bot shutting down") except Exception as e: logger.error(f"Bot crashed: {str(e)}") + sys.exit(1) # Exit with error code for crash finally: logger.info("Bot shutdown complete") + sys.exit(0) # Explicit clean exit