diff --git a/homelab-ai-bot/telegram_bot.py b/homelab-ai-bot/telegram_bot.py index 5774d6a2..2c683bad 100644 --- a/homelab-ai-bot/telegram_bot.py +++ b/homelab-ai-bot/telegram_bot.py @@ -128,6 +128,7 @@ log = logging.getLogger("hausmeister") ALLOWED_CHAT_IDS: set[int] = set() CHAT_ID: int | None = None ACTIVE_LLM_TASKS: dict[int, asyncio.Task] = {} +_BACKGROUND_TASKS: list[asyncio.Task] = [] @@ -991,22 +992,28 @@ async def handle_callback(update: Update, ctx: ContextTypes.DEFAULT_TYPE): -async def _send_daily_forecast(context): +async def _send_daily_forecast(job_context): """Taeglich 08:00 Uhr: Systemdaten sammeln, LLM analysiert, Ergebnis senden.""" if not CHAT_ID: return - bot = getattr(context, "bot", None) or context + bot = getattr(job_context, "bot", None) or job_context try: from tools.predict import handle_get_health_forecast - from llm import ask_with_tools - report = await asyncio.get_event_loop().run_in_executor(None, handle_get_health_forecast) + report = await asyncio.to_thread(handle_get_health_forecast) prompt = ( "Morgendlicher System-Check. Analysiere diesen Report und gib eine kurze " "Prognose ob sich Probleme anbahnen. Nur echte Auffaelligkeiten nennen, " "klare Handlungsempfehlung wenn noetig. Bei allem OK: kurze Entwarnung." "\n\n" + report ) - analysis = await asyncio.get_event_loop().run_in_executor(None, ask_with_tools, prompt) + handlers = context.get_tool_handlers(session_id=None) + analysis = await asyncio.to_thread( + llm.ask_with_tools, + prompt, + handlers, + session_id=None, + document_mode=False, + ) msg = "🔭 *Taegliche Systemvorhersage*\n\n" + analysis await bot.send_message(chat_id=CHAT_ID, text=msg, parse_mode="Markdown") log.info("Taegl. Systemvorhersage gesendet") @@ -1101,7 +1108,22 @@ def main(): signal.signal(signal.SIGTERM, lambda *_: sys.exit(0)) log.info("Starte Orbitalo Hausmeister-Bot...") - app = Application.builder().token(token).concurrent_updates(True).build() + + async def post_shutdown(application): + for t in _BACKGROUND_TASKS: + if not t.done(): + t.cancel() + if _BACKGROUND_TASKS: + await asyncio.gather(*_BACKGROUND_TASKS, return_exceptions=True) + _BACKGROUND_TASKS.clear() + + app = ( + Application.builder() + .token(token) + .concurrent_updates(True) + .post_shutdown(post_shutdown) + .build() + ) app.add_handler(CommandHandler("start", cmd_start)) app.add_handler(CommandHandler("status", cmd_status)) @@ -1181,13 +1203,13 @@ def main(): async def post_init(application): await application.bot.set_my_commands(BOT_COMMANDS) log.info("Kommandomenü registriert") - asyncio.create_task(_watchdog_loop()) - asyncio.create_task(asyncio.to_thread(llm.warmup_ollama)) - asyncio.create_task(_monitor_loop(application)) + _BACKGROUND_TASKS.append(asyncio.create_task(_watchdog_loop())) + _BACKGROUND_TASKS.append(asyncio.create_task(asyncio.to_thread(llm.warmup_ollama))) + _BACKGROUND_TASKS.append(asyncio.create_task(_monitor_loop(application))) log.info("Monitor-Loop aktiv (alle 10 Min)") if application.job_queue is None: - asyncio.create_task(_filmtipp_loop(application)) - asyncio.create_task(_forecast_loop(application)) + _BACKGROUND_TASKS.append(asyncio.create_task(_filmtipp_loop(application))) + _BACKGROUND_TASKS.append(asyncio.create_task(_forecast_loop(application))) _sd_notify("READY=1") log.info("Systemd Watchdog aktiv (50s Intervall)")