mirror of
https://github.com/pacnpal/Pac-cogs.git
synced 2025-12-20 10:51:05 -05:00
Improve error handling and task management
- Add custom exception classes for better error handling - Add better error logging to Discord channels with retries - Add proper task tracking with error callbacks - Add better cleanup and resource management - Add better version comparison for updates - Add retries for Discord API operations - Add better error context and recovery - Add better component lifecycle management
This commit is contained in:
@@ -19,6 +19,8 @@ from datetime import datetime, timedelta
|
|||||||
import traceback
|
import traceback
|
||||||
import contextlib
|
import contextlib
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
import pkg_resources
|
||||||
|
from packaging import version
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
@@ -41,6 +43,14 @@ class ProcessingError(Exception):
|
|||||||
"""Custom exception for video processing errors"""
|
"""Custom exception for video processing errors"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class DiscordAPIError(ProcessingError):
|
||||||
|
"""Raised when Discord API operations fail"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
class UpdateError(ProcessingError):
|
||||||
|
"""Raised when update operations fail"""
|
||||||
|
pass
|
||||||
|
|
||||||
class VideoArchiver(commands.Cog):
|
class VideoArchiver(commands.Cog):
|
||||||
"""Archive videos from Discord channels"""
|
"""Archive videos from Discord channels"""
|
||||||
|
|
||||||
@@ -61,7 +71,9 @@ class VideoArchiver(commands.Cog):
|
|||||||
"disable_update_check": False,
|
"disable_update_check": False,
|
||||||
"last_update_check": None,
|
"last_update_check": None,
|
||||||
"max_retries": 3,
|
"max_retries": 3,
|
||||||
"retry_delay": 5
|
"retry_delay": 5,
|
||||||
|
"discord_retry_attempts": 3, # New setting for Discord API retries
|
||||||
|
"discord_retry_delay": 5, # New setting for Discord API retry delay
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, bot: Red):
|
def __init__(self, bot: Red):
|
||||||
@@ -96,9 +108,24 @@ class VideoArchiver(commands.Cog):
|
|||||||
if guild_id not in self.active_tasks:
|
if guild_id not in self.active_tasks:
|
||||||
self.active_tasks[guild_id] = set()
|
self.active_tasks[guild_id] = set()
|
||||||
self.active_tasks[guild_id].add(task)
|
self.active_tasks[guild_id].add(task)
|
||||||
task.add_done_callback(
|
|
||||||
lambda t: asyncio.create_task(self.remove_task(guild_id, t))
|
# Add error handling callback
|
||||||
)
|
def handle_task_error(t):
|
||||||
|
try:
|
||||||
|
exc = t.exception()
|
||||||
|
if exc:
|
||||||
|
asyncio.create_task(self.log_error(
|
||||||
|
self.bot.get_guild(guild_id),
|
||||||
|
exc,
|
||||||
|
"Task error"
|
||||||
|
))
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Remove task
|
||||||
|
asyncio.create_task(self.remove_task(guild_id, t))
|
||||||
|
|
||||||
|
task.add_done_callback(handle_task_error)
|
||||||
|
|
||||||
async def remove_task(self, guild_id: int, task: asyncio.Task):
|
async def remove_task(self, guild_id: int, task: asyncio.Task):
|
||||||
"""Remove a completed task"""
|
"""Remove a completed task"""
|
||||||
@@ -194,8 +221,17 @@ class VideoArchiver(commands.Cog):
|
|||||||
else:
|
else:
|
||||||
error_parts.append(tb)
|
error_parts.append(tb)
|
||||||
|
|
||||||
|
# Send error messages with retries
|
||||||
for part in error_parts:
|
for part in error_parts:
|
||||||
|
for attempt in range(settings["discord_retry_attempts"]):
|
||||||
|
try:
|
||||||
await log_channel.send(f"```py\n{part}```")
|
await log_channel.send(f"```py\n{part}```")
|
||||||
|
break
|
||||||
|
except discord.HTTPException as e:
|
||||||
|
if attempt == settings["discord_retry_attempts"] - 1:
|
||||||
|
logger.error(f"Failed to send error log to channel after {attempt + 1} attempts: {str(e)}")
|
||||||
|
else:
|
||||||
|
await asyncio.sleep(settings["discord_retry_delay"])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to send error log to channel: {str(e)}")
|
logger.error(f"Failed to send error log to channel: {str(e)}")
|
||||||
|
|
||||||
@@ -248,17 +284,31 @@ class VideoArchiver(commands.Cog):
|
|||||||
current_time.isoformat()
|
current_time.isoformat()
|
||||||
)
|
)
|
||||||
|
|
||||||
if current_version != latest_version:
|
# Compare versions properly
|
||||||
|
if version.parse(current_version) < version.parse(latest_version):
|
||||||
owner = self.bot.get_user(self.bot.owner_id)
|
owner = self.bot.get_user(self.bot.owner_id)
|
||||||
if owner:
|
if owner:
|
||||||
|
# Send notification with retries
|
||||||
|
for attempt in range(settings["discord_retry_attempts"]):
|
||||||
|
try:
|
||||||
await owner.send(
|
await owner.send(
|
||||||
f"⚠️ A new version of yt-dlp is available!\n"
|
f"⚠️ A new version of yt-dlp is available!\n"
|
||||||
f"Current: {current_version}\n"
|
f"Current: {current_version}\n"
|
||||||
f"Latest: {latest_version}\n"
|
f"Latest: {latest_version}\n"
|
||||||
f"Use `[p]videoarchiver updateytdlp` to update."
|
f"Use `[p]videoarchiver updateytdlp` to update."
|
||||||
)
|
)
|
||||||
|
break
|
||||||
|
except discord.HTTPException:
|
||||||
|
if attempt == settings["discord_retry_attempts"] - 1:
|
||||||
|
await self.log_error(
|
||||||
|
guild,
|
||||||
|
Exception("Failed to send update notification to owner"),
|
||||||
|
"checking for updates"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise Exception(f"GitHub API returned status {response.status}")
|
await asyncio.sleep(settings["discord_retry_delay"])
|
||||||
|
else:
|
||||||
|
raise UpdateError(f"GitHub API returned status {response.status}")
|
||||||
|
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
await self.log_error(
|
await self.log_error(
|
||||||
|
|||||||
Reference in New Issue
Block a user