Add background loop health check#1472
Conversation
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
📝 WalkthroughWalkthroughAdds BackgroundLoopHealthCheck: a non-critical health check that fetches LoopCog, returns critical if missing, otherwise calls is_running() on configured background loop tasks and returns degraded (listing stopped loops) or healthy. ChangesBackground Loop Health Check
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@extensions/health_check.py`:
- Around line 1-79: Replace the Markdown blob with a valid Python module that
defines BackgroundLoopHealthCheck: add imports (from __future__ annotations,
discord.ext.commands, and HealthCheck/HealthCheckResult/HealthStatus), implement
class BackgroundLoopHealthCheck(bot: commands.Bot) with properties name and
critical, and an async run() method that calls self.bot.get_cog("LoopCog")
(check cog is None), builds the loop_tasks list referencing the cog methods
(sendSendReadyGiveaways, endGiveawaysLoop, checkVoiceUsers, addVoiceUserLoop,
refillAiTokenLoop, pingServerLoop, backupDatabaseLoop,
removeExpiredClaimedBoosterRoles, removeExpiredClaimedBoosterChannels,
sendScheduledMessages, pollTwitchStreams), computes failed_loops via
task.is_running(), and returns HealthCheckResult with HealthStatus.CRITICAL if
cog missing, HealthStatus.DEGRADED with details when failed_loops nonempty, or
HealthStatus.HEALTHY otherwise.
- Around line 39-51: The health check's loop_tasks list is missing the
clearNotifiedUsersLoop and sendPokemonWerbung background loops, causing false
positives; update the loop_tasks array (where it's defined) to include entries
like ("Clear Notified Users", cog.clearNotifiedUsersLoop) and ("Pokemon
Werbung", cog.sendPokemonWerbung) so those loops are checked alongside
cog.sendSendReadyGiveaways, cog.endGiveawaysLoop, etc.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: bdde44a3-4deb-45e6-97f5-6eeaf0bdf09a
📒 Files selected for processing (1)
extensions/health_check.py
| # Background Loop Health Check | ||
|
|
||
| Requires the HealthCheck framework from the main health check issue. | ||
|
|
||
| The bot relies on multiple background task loops (`extensions/loops.py`): | ||
| - Giveaway sending (10s) | ||
| - Giveaway ending (10s) | ||
| - Voice XP processing (5s) | ||
| - AI token refill (60s) | ||
| - Server pinging (5s) | ||
| - Database backup (1h) | ||
| - Booster role/channel cleanup (10s) | ||
| - Scheduled messages (10s) | ||
| - Twitch polling (10s) | ||
|
|
||
| If one of these loops crashes silently (they all use `except Exception: pass`), the feature stops working without any notification. | ||
|
|
||
| ## Implementation | ||
|
|
||
| ```python | ||
| class BackgroundLoopHealthCheck(HealthCheck): | ||
| def __init__(self, bot): | ||
| self.bot = bot | ||
|
|
||
| @property | ||
| def name(self) -> str: return "Background Loops" | ||
| @property | ||
| def critical(self) -> bool: return False # Individual loops failing is degraded, not critical | ||
|
|
||
| async def run(self) -> HealthCheckResult: | ||
| cog = self.bot.get_cog("LoopCog") | ||
| if not cog: | ||
| return HealthCheckResult( | ||
| self.name, HealthStatus.CRITICAL, | ||
| "LoopCog not found. No background tasks registered." | ||
| ) | ||
|
|
||
| # Check each loop task | ||
| loop_tasks = [ | ||
| ("Giveaway Sender", cog.sendSendReadyGiveaways), | ||
| ("Giveaway Ender", cog.endGiveawaysLoop), | ||
| ("Voice Checker", cog.checkVoiceUsers), | ||
| ("Voice XP", cog.addVoiceUserLoop), | ||
| ("AI Token Refill", cog.refillAiTokenLoop), | ||
| ("Ping Server", cog.pingServerLoop), | ||
| ("Database Backup", cog.backupDatabaseLoop), | ||
| ("Booster Roles", cog.removeExpiredClaimedBoosterRoles), | ||
| ("Booster Channels", cog.removeExpiredClaimedBoosterChannels), | ||
| ("Scheduled Messages", cog.sendScheduledMessages), | ||
| ("Twitch Polling", cog.pollTwitchStreams) | ||
| ] | ||
|
|
||
| failed_loops = [] | ||
| for name, task in loop_tasks: | ||
| if not task.is_running(): | ||
| failed_loops.append(name) | ||
| # Optionally check how long since last iteration | ||
| # if task.delta and task.delta.total_seconds() > expected_interval * 3: | ||
| # failed_loops.append(f"{name} (stuck)") | ||
|
|
||
| if failed_loops: | ||
| return HealthCheckResult( | ||
| self.name, HealthStatus.DEGRADED, | ||
| f"Stopped loops: {', '.join(failed_loops)}", | ||
| details={"stopped_loops": failed_loops} | ||
| ) | ||
|
|
||
| return HealthCheckResult( | ||
| self.name, HealthStatus.HEALTHY, | ||
| f"All {len(loop_tasks)} background loops are running." | ||
| ) | ||
| ``` | ||
|
|
||
| ## Checks | ||
|
|
||
| - **Critical**: No (startup check would always pass since loops start after ready) | ||
| - **Startup check**: No | ||
| - **Periodic check**: Yes (every 2 minutes - detects failures quickly) | ||
| - **Failure action**: Notify alert channel with which loop(s) stopped No newline at end of file |
There was a problem hiding this comment.
Replace Markdown prose with executable Python module code.
extensions/health_check.py currently contains raw Markdown text, so Python cannot parse it (e.g., Line 3, Line 6). This blocks import, lint, and type-check entirely.
Proposed fix (convert to valid module code)
-# Background Loop Health Check
-
-Requires the HealthCheck framework from the main health check issue.
-
-The bot relies on multiple background task loops (`extensions/loops.py`):
-- Giveaway sending (10s)
-- Giveaway ending (10s)
-- Voice XP processing (5s)
-- AI token refill (60s)
-- Server pinging (5s)
-- Database backup (1h)
-- Booster role/channel cleanup (10s)
-- Scheduled messages (10s)
-- Twitch polling (10s)
-
-If one of these loops crashes silently (they all use `except Exception: pass`), the feature stops working without any notification.
-
-## Implementation
-
-```python
-class BackgroundLoopHealthCheck(HealthCheck):
- def __init__(self, bot):
- self.bot = bot
-
- `@property`
- def name(self) -> str: return "Background Loops"
- `@property`
- def critical(self) -> bool: return False # Individual loops failing is degraded, not critical
-
- async def run(self) -> HealthCheckResult:
- cog = self.bot.get_cog("LoopCog")
- if not cog:
- return HealthCheckResult(
- self.name, HealthStatus.CRITICAL,
- "LoopCog not found. No background tasks registered."
- )
-
- # Check each loop task
- loop_tasks = [
- ("Giveaway Sender", cog.sendSendReadyGiveaways),
- ("Giveaway Ender", cog.endGiveawaysLoop),
- ("Voice Checker", cog.checkVoiceUsers),
- ("Voice XP", cog.addVoiceUserLoop),
- ("AI Token Refill", cog.refillAiTokenLoop),
- ("Ping Server", cog.pingServerLoop),
- ("Database Backup", cog.backupDatabaseLoop),
- ("Booster Roles", cog.removeExpiredClaimedBoosterRoles),
- ("Booster Channels", cog.removeExpiredClaimedBoosterChannels),
- ("Scheduled Messages", cog.sendScheduledMessages),
- ("Twitch Polling", cog.pollTwitchStreams)
- ]
-
- failed_loops = []
- for name, task in loop_tasks:
- if not task.is_running():
- failed_loops.append(name)
- # Optionally check how long since last iteration
- # if task.delta and task.delta.total_seconds() > expected_interval * 3:
- # failed_loops.append(f"{name} (stuck)")
-
- if failed_loops:
- return HealthCheckResult(
- self.name, HealthStatus.DEGRADED,
- f"Stopped loops: {', '.join(failed_loops)}",
- details={"stopped_loops": failed_loops}
- )
-
- return HealthCheckResult(
- self.name, HealthStatus.HEALTHY,
- f"All {len(loop_tasks)} background loops are running."
- )
-```
-
-## Checks
-
-- **Critical**: No (startup check would always pass since loops start after ready)
-- **Startup check**: No
-- **Periodic check**: Yes (every 2 minutes - detects failures quickly)
-- **Failure action**: Notify alert channel with which loop(s) stopped
+from __future__ import annotations
+
+from discord.ext import commands
+from health_check import HealthCheck, HealthCheckResult, HealthStatus
+
+
+class BackgroundLoopHealthCheck(HealthCheck):
+ def __init__(self, bot: commands.Bot) -> None:
+ self.bot = bot
+
+ `@property`
+ def name(self) -> str:
+ return "Background Loops"
+
+ `@property`
+ def critical(self) -> bool:
+ return False
+
+ async def run(self) -> HealthCheckResult:
+ cog = self.bot.get_cog("LoopCog")
+ if cog is None:
+ return HealthCheckResult(
+ self.name,
+ HealthStatus.CRITICAL,
+ "LoopCog not found. No background tasks registered.",
+ )
+
+ loop_tasks = [
+ ("Giveaway Sender", cog.sendSendReadyGiveaways),
+ ("Giveaway Ender", cog.endGiveawaysLoop),
+ ("Voice Checker", cog.checkVoiceUsers),
+ ("Voice XP", cog.addVoiceUserLoop),
+ ("AI Token Refill", cog.refillAiTokenLoop),
+ ("Ping Server", cog.pingServerLoop),
+ ("Database Backup", cog.backupDatabaseLoop),
+ ("Booster Roles", cog.removeExpiredClaimedBoosterRoles),
+ ("Booster Channels", cog.removeExpiredClaimedBoosterChannels),
+ ("Scheduled Messages", cog.sendScheduledMessages),
+ ("Twitch Polling", cog.pollTwitchStreams),
+ ]
+
+ failed_loops = [name for name, task in loop_tasks if not task.is_running()]
+ if failed_loops:
+ return HealthCheckResult(
+ self.name,
+ HealthStatus.DEGRADED,
+ f"Stopped loops: {', '.join(failed_loops)}",
+ details={"stopped_loops": failed_loops},
+ )
+
+ return HealthCheckResult(
+ self.name,
+ HealthStatus.HEALTHY,
+ f"All {len(loop_tasks)} background loops are running.",
+ )🧰 Tools
🪛 Flake8 (7.3.0)
[error] 6-6: SyntaxError: invalid decimal literal
(E999)
🪛 GitHub Actions: Python Type Checking with Issue Management / 0_type-check (3.12).txt
[error] 6-6: mypy syntax error: invalid decimal literal [syntax]. Command: mypy . --explicit-package-bases --soft-error-limit -1 --show-error-codes --no-error-summary --disallow-untyped-defs --disallow-incomplete-defs --no-implicit-optional --warn-return-any --warn-unused-ignores --warn-redundant-casts --warn-unreachable
🪛 GitHub Actions: Python Type Checking with Issue Management / type-check (3.12)
[error] 6-6: mypy: invalid decimal literal [syntax].
🪛 GitHub Actions: Ruff Lint & Format / 0_lint_and_format.txt
[error] 3-3: ruff format failed to parse extensions/health_check.py:3:10: Simple statements must be separated by newlines or semicolons.
🪛 GitHub Actions: Ruff Lint & Format / lint_and_format
[error] 3-3: ruff format failed: Failed to parse extensions/health_check.py:3:10: Simple statements must be separated by newlines or semicolons
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@extensions/health_check.py` around lines 1 - 79, Replace the Markdown blob
with a valid Python module that defines BackgroundLoopHealthCheck: add imports
(from __future__ annotations, discord.ext.commands, and
HealthCheck/HealthCheckResult/HealthStatus), implement class
BackgroundLoopHealthCheck(bot: commands.Bot) with properties name and critical,
and an async run() method that calls self.bot.get_cog("LoopCog") (check cog is
None), builds the loop_tasks list referencing the cog methods
(sendSendReadyGiveaways, endGiveawaysLoop, checkVoiceUsers, addVoiceUserLoop,
refillAiTokenLoop, pingServerLoop, backupDatabaseLoop,
removeExpiredClaimedBoosterRoles, removeExpiredClaimedBoosterChannels,
sendScheduledMessages, pollTwitchStreams), computes failed_loops via
task.is_running(), and returns HealthCheckResult with HealthStatus.CRITICAL if
cog missing, HealthStatus.DEGRADED with details when failed_loops nonempty, or
HealthStatus.HEALTHY otherwise.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
extensions/health_check.py (1)
1-83:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winThe file is still Markdown prose, blocking all Python tooling.
This file remains in raw Markdown format and cannot be parsed as a Python module. Lines 22-76 contain Python code embedded in a Markdown code fence (
\``python ... ````), but Python interpreters, linters, and type checkers cannot execute or analyze it. The pipeline failures (mypy syntax error at line 6, ruff parse failure at line 3) confirm that this critical issue from the previous review is unresolved.While lines 52-54 correctly add the two missing loops (
clearNotifiedUsersLoopandsendPokemonWerbung) to the embedded code, these changes have no effect until the file is converted to a valid Python module with proper imports and executable class definitions.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@extensions/health_check.py` around lines 1 - 83, This file is still plain Markdown with a fenced Python snippet, causing parse errors; convert it into a real Python module by removing the Markdown prose and backticks, add necessary imports (HealthCheck, HealthCheckResult, HealthStatus, typing if needed), and implement the BackgroundLoopHealthCheck class as executable code using the run method shown; reference the cog look-up (self.bot.get_cog("LoopCog")) and the loop task names/methods (sendSendReadyGiveaways, endGiveawaysLoop, checkVoiceUsers, addVoiceUserLoop, refillAiTokenLoop, pingServerLoop, backupDatabaseLoop, removeExpiredClaimedBoosterRoles, removeExpiredClaimedBoosterChannels, sendScheduledMessages, pollTwitchStreams, clearNotifiedUsersLoop, sendPokemonWerbung) so linters/mypy can import and type-check them, and place the human-readable description in module docstring or separate docs rather than leaving Markdown fences in the .py file.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@extensions/health_check.py`:
- Around line 1-83: This file is still plain Markdown with a fenced Python
snippet, causing parse errors; convert it into a real Python module by removing
the Markdown prose and backticks, add necessary imports (HealthCheck,
HealthCheckResult, HealthStatus, typing if needed), and implement the
BackgroundLoopHealthCheck class as executable code using the run method shown;
reference the cog look-up (self.bot.get_cog("LoopCog")) and the loop task
names/methods (sendSendReadyGiveaways, endGiveawaysLoop, checkVoiceUsers,
addVoiceUserLoop, refillAiTokenLoop, pingServerLoop, backupDatabaseLoop,
removeExpiredClaimedBoosterRoles, removeExpiredClaimedBoosterChannels,
sendScheduledMessages, pollTwitchStreams, clearNotifiedUsersLoop,
sendPokemonWerbung) so linters/mypy can import and type-check them, and place
the human-readable description in module docstring or separate docs rather than
leaving Markdown fences in the .py file.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 2f465ee0-6033-4235-b4bc-d2c10ae1cd98
📒 Files selected for processing (1)
extensions/health_check.py
* Add background loop health check implementation * Add additional background loops to health check * Add clearNotifiedUsersLoop and sendPokemonWerbung to health check --------- Co-authored-by: EntchenEric <entcheneric@users.noreply.github.com>
This PR implements a health check for all background loops in the bot, ensuring they are running as expected.
Summary by CodeRabbit