fix(tasks): replace fire-and-forget asyncio.create_task with create_tracked_task

Add utils/task_tracker.py with create_tracked_task() that wraps background
tasks with error logging, cancellation handling, and reference tracking.

Replace all 17 fire-and-forget asyncio.create_task() calls across 7 files:
- bot/bot.py (5 interjection checks)
- bot/utils/autonomous.py (2 check-and-act/react tasks)
- bot/utils/bipolar_mode.py (3 argument tasks)
- bot/commands/uno.py (1 game loop task)
- bot/utils/voice_receiver.py (3 STT/interruption callbacks)
- bot/utils/persona_dialogue.py (4 dialogue turn/interjection tasks)

Previously-tracked tasks (voice_audio.py, voice_manager.py) were left as-is
since they already store task references for cancellation.

Closes #1
This commit is contained in:
2026-02-18 12:01:08 +02:00
parent cf55b15745
commit 7b7abcfc68
7 changed files with 104 additions and 25 deletions

View File

@@ -10,6 +10,9 @@ import signal
import atexit
from api import app
# Import new configuration system
from config import CONFIG, SECRETS, validate_config, print_config_summary
from server_manager import server_manager
from utils.scheduled import (
send_monday_video
@@ -36,7 +39,7 @@ from utils.media import(
)
from utils.llm import query_llama
from utils.autonomous import (
setup_autonomous_speaking,
setup_autonomous_speaking,
load_last_sent_tweets,
# V2 imports
on_message_event,
@@ -47,12 +50,26 @@ from utils.autonomous import (
from utils.dm_logger import dm_logger
from utils.dm_interaction_analyzer import init_dm_analyzer
from utils.logger import get_logger
from utils.task_tracker import create_tracked_task
import globals
# Initialize bot logger
logger = get_logger('bot')
# Validate configuration on startup
is_valid, validation_errors = validate_config()
if not is_valid:
logger.error("❌ Configuration validation failed!")
for error in validation_errors:
logger.error(f" - {error}")
logger.error("Please check your .env file and restart.")
sys.exit(1)
# Print configuration summary for debugging
if CONFIG.autonomous.debug_mode:
print_config_summary()
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s: %(message)s",
@@ -281,7 +298,7 @@ async def on_message(message):
try:
from utils.persona_dialogue import check_for_interjection
current_persona = "evil" if globals.EVIL_MODE else "miku"
asyncio.create_task(check_for_interjection(response_message, current_persona))
create_tracked_task(check_for_interjection(response_message, current_persona), task_name="interjection_check")
except Exception as e:
logger.error(f"Error checking for persona interjection: {e}")
@@ -353,7 +370,7 @@ async def on_message(message):
try:
from utils.persona_dialogue import check_for_interjection
current_persona = "evil" if globals.EVIL_MODE else "miku"
asyncio.create_task(check_for_interjection(response_message, current_persona))
create_tracked_task(check_for_interjection(response_message, current_persona), task_name="interjection_check")
except Exception as e:
logger.error(f"Error checking for persona interjection: {e}")
@@ -435,7 +452,7 @@ async def on_message(message):
try:
from utils.persona_dialogue import check_for_interjection
current_persona = "evil" if globals.EVIL_MODE else "miku"
asyncio.create_task(check_for_interjection(response_message, current_persona))
create_tracked_task(check_for_interjection(response_message, current_persona), task_name="interjection_check")
except Exception as e:
logger.error(f"Error checking for persona interjection: {e}")
@@ -557,7 +574,7 @@ async def on_message(message):
try:
from utils.persona_dialogue import check_for_interjection
current_persona = "evil" if globals.EVIL_MODE else "miku"
asyncio.create_task(check_for_interjection(response_message, current_persona))
create_tracked_task(check_for_interjection(response_message, current_persona), task_name="interjection_check")
except Exception as e:
logger.error(f"Error checking for persona interjection: {e}")
@@ -650,7 +667,7 @@ async def on_message(message):
current_persona = "evil" if globals.EVIL_MODE else "miku"
logger.debug(f"Creating interjection check task for persona: {current_persona}")
# Pass the bot's response message for analysis
asyncio.create_task(check_for_interjection(response_message, current_persona))
create_tracked_task(check_for_interjection(response_message, current_persona), task_name="interjection_check")
except Exception as e:
logger.error(f"Error checking for persona interjection: {e}")
import traceback