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:
@@ -253,7 +253,10 @@ class Bot:
|
|||||||
async def _loop(self) -> None:
|
async def _loop(self) -> None:
|
||||||
"""Read and dispatch messages until disconnect."""
|
"""Read and dispatch messages until disconnect."""
|
||||||
while self._running:
|
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:
|
if line is None:
|
||||||
log.warning("server closed connection")
|
log.warning("server closed connection")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import sys
|
|||||||
from derp import __version__
|
from derp import __version__
|
||||||
from derp.bot import Bot
|
from derp.bot import Bot
|
||||||
from derp.config import build_server_configs, resolve_config
|
from derp.config import build_server_configs, resolve_config
|
||||||
|
from derp.irc import format_msg
|
||||||
from derp.log import JsonFormatter
|
from derp.log import JsonFormatter
|
||||||
from derp.plugin import PluginRegistry
|
from derp.plugin import PluginRegistry
|
||||||
|
|
||||||
@@ -72,12 +73,24 @@ def _run(bots: list) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def _shutdown(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")
|
logging.getLogger("derp").info("SIGTERM received, shutting down")
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
for bot in bots:
|
for bot in bots:
|
||||||
bot._running = False
|
bot._running = False
|
||||||
if hasattr(bot, "conn"):
|
if hasattr(bot, "conn") and bot.conn.connected:
|
||||||
asyncio.get_running_loop().create_task(bot.conn.close())
|
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:
|
def _dump_tracemalloc(log: logging.Logger, path: str, limit: int = 25) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user