fix: graceful SIGTERM shutdown for IRC and Mumble bots

Send IRC QUIT before closing the socket so the server releases the nick
immediately. Wrap readline() in wait_for(timeout=2.0) so the _running
check triggers even when the server is quiet. Explicitly stop pymumble
in the signal handler to accelerate Mumble teardown. Together these
eliminate the 10s podman grace-period SIGKILL.
This commit is contained in:
user
2026-02-22 20:31:49 +01:00
parent 0ffddb8e41
commit a76d46b1de
2 changed files with 20 additions and 4 deletions

View File

@@ -253,7 +253,10 @@ class Bot:
async def _loop(self) -> None:
"""Read and dispatch messages until disconnect."""
while self._running:
line = await self.conn.readline()
try:
line = await asyncio.wait_for(self.conn.readline(), timeout=2.0)
except asyncio.TimeoutError:
continue
if line is None:
log.warning("server closed connection")
return

View File

@@ -10,6 +10,7 @@ import sys
from derp import __version__
from derp.bot import Bot
from derp.config import build_server_configs, resolve_config
from derp.irc import format_msg
from derp.log import JsonFormatter
from derp.plugin import PluginRegistry
@@ -72,12 +73,24 @@ def _run(bots: list) -> None:
def _shutdown(bots: list) -> None:
"""Signal handler: stop all bot loops so cProfile can flush."""
"""Signal handler: stop all bot loops and tear down connections."""
logging.getLogger("derp").info("SIGTERM received, shutting down")
loop = asyncio.get_running_loop()
for bot in bots:
bot._running = False
if hasattr(bot, "conn"):
asyncio.get_running_loop().create_task(bot.conn.close())
if hasattr(bot, "conn") and bot.conn.connected:
loop.create_task(_quit_and_close(bot))
elif hasattr(bot, "_mumble") and bot._mumble:
bot._mumble.stop()
async def _quit_and_close(bot) -> None:
"""Send IRC QUIT and close the connection."""
try:
await bot.conn.send(format_msg("QUIT", "shutting down"))
except Exception:
pass
await bot.conn.close()
def _dump_tracemalloc(log: logging.Logger, path: str, limit: int = 25) -> None: