fix: delete mod action logs in chat after 2 mins#84
Conversation
WalkthroughMade moderation logging fire-and-forget and added a timed cleanup: Changes
Sequence Diagram(s)sequenceDiagram
participant Moderator as ModeratorAction
participant Logger as TgLogger
participant Telegram as TelegramAPI
Moderator->>Logger: void logModActionInChat(props)
Logger->>Telegram: sendMessage(chatId, content)
Telegram-->>Logger: sent(message_id)
Logger->>Logger: after(120000)
Note right of Logger: wait 120s without blocking caller
Logger->>Telegram: deleteMessage(chatId, message_id)
Telegram-->>Logger: deleteResult / error
Possibly related PRs
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/modules/tg-logger/index.ts (1)
527-539:⚠️ Potential issue | 🟠 MajorAvoid blocking this method for 120 seconds.
Because
logModActionInChatis awaited bymoderationAction, Line 532 makes the whole moderation path wait 2 minutes before returning. This is a major reliability/perf regression under load. Also, the shared catch message is now inaccurate for delete failures.Suggested non-blocking rewrite
- await this.shared.api - .sendMessage(p.chat.id, msg, { - disable_notification: false, - link_preview_options: { is_disabled: true }, - }) - .then(after(120_000)) - .then((sent) => this.shared.api.deleteMessage(p.chat.id, sent.message_id)) - .catch((error: unknown) => { - logger.warn( - { error, action: p.action }, - "[Moderation:logActionInChat] Failed to post moderation action in chat" - ) - }) + const sent = await this.shared.api + .sendMessage(p.chat.id, msg, { + disable_notification: false, + link_preview_options: { is_disabled: true }, + }) + .catch((error: unknown) => { + logger.warn( + { error, action: p.action }, + "[Moderation:logActionInChat] Failed to post moderation action in chat" + ) + return null + }) + + if (!sent) return + + void after(120_000)(sent) + .then((m) => this.shared.api.deleteMessage(p.chat.id, m.message_id)) + .catch((error: unknown) => { + logger.warn( + { error, action: p.action, messageId: sent.message_id }, + "[Moderation:logActionInChat] Failed to delete moderation action message" + ) + })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/modules/tg-logger/index.ts` around lines 527 - 539, The current chain in logModActionInChat awaits sendMessage.then(after(120_000)) which blocks moderationAction for 120s; change this to fire-and-forget: call this.shared.api.sendMessage(...) without awaiting (use void or assign to an unawaited promise) and chain the deletion and error handling on that promise so logModActionInChat returns immediately; separate error handlers so failures to delete the message are logged as delete errors (e.g., "Failed to delete moderation message") while sendMessage failures remain "Failed to post moderation action in chat", and keep the original options (disable_notification/link_preview_options) when creating the background promise.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@src/modules/tg-logger/index.ts`:
- Around line 527-539: The current chain in logModActionInChat awaits
sendMessage.then(after(120_000)) which blocks moderationAction for 120s; change
this to fire-and-forget: call this.shared.api.sendMessage(...) without awaiting
(use void or assign to an unawaited promise) and chain the deletion and error
handling on that promise so logModActionInChat returns immediately; separate
error handlers so failures to delete the message are logged as delete errors
(e.g., "Failed to delete moderation message") while sendMessage failures remain
"Failed to post moderation action in chat", and keep the original options
(disable_notification/link_preview_options) when creating the background
promise.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 46e63a60-21dd-48da-9684-4793d658cc47
📒 Files selected for processing (2)
src/modules/tg-logger/index.tssrc/utils/wait.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/modules/tg-logger/index.ts (2)
532-537: Separate send and delete failure paths in logs.Line 537 always says “Failed to post moderation action in chat”, but this catch now also includes delayed delete failures. This makes incident triage noisy/misleading.
Suggested refactor
- await this.shared.api - .sendMessage(p.chat.id, msg, { - disable_notification: false, - link_preview_options: { is_disabled: true }, - }) - .then(after(120_000)) - .then((sent) => this.shared.api.deleteMessage(p.chat.id, sent.message_id)) - .catch((error: unknown) => { - logger.warn( - { error, action: p.action }, - "[Moderation:logActionInChat] Failed to post moderation action in chat" - ) - }) + const sent = await this.shared.api + .sendMessage(p.chat.id, msg, { + disable_notification: false, + link_preview_options: { is_disabled: true }, + }) + .catch((error: unknown) => { + logger.warn({ error, action: p.action }, "[Moderation:logActionInChat] Failed to post moderation action in chat") + return null + }) + if (!sent) return + + await after(120_000)(sent) + await this.shared.api.deleteMessage(p.chat.id, sent.message_id).catch((error: unknown) => { + logger.warn({ error, action: p.action }, "[Moderation:logActionInChat] Failed to delete timed moderation action log") + })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/modules/tg-logger/index.ts` around lines 532 - 537, The current promise chain conflates send and delayed-delete failures into one catch, causing misleading logs; separate the send and delete failure paths by handling the delete error locally: call the send promise (the code using after(120_000) and the send that returns "sent"), then in its .then attach a .catch on this.shared.api.deleteMessage(p.chat.id, sent.message_id) to log a clear "Failed to delete moderation message" via logger.warn (include { error, action: p.action }), and keep a top-level catch only for the original send failure and log "Failed to post moderation action in chat" (include { error, action: p.action }); reference the after helper, the sent variable, this.shared.api.deleteMessage, and logger.warn to find where to change the chain.
532-533: If deletion after 2 minutes is strict, this is best-effort only.Lines 532-533 rely on an in-memory timer; a restart in that 2-minute window leaves logs undeleted. Consider a small persistent cleanup queue if this behavior must be guaranteed.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/modules/tg-logger/index.ts` around lines 532 - 533, The current post-send deletion chain uses an in-memory timer (.then(after(120_000))) so a process restart can leave messages undeleted; replace this best-effort timer with a small persistent cleanup queue: after sending (where .then((sent) => this.shared.api.deleteMessage(p.chat.id, sent.message_id)) is used) persist the tuple {chatId: p.chat.id, messageId: sent.message_id, deleteAt: now+120s} to durable storage and have a background worker/cron (or a restart-on-boot reconciler) that reads pending entries and calls shared.api.deleteMessage(chatId, messageId) when deleteAt is reached and removes the entry upon success, while keeping the original in-memory timer only as an optimization.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/modules/tg-logger/index.ts`:
- Line 282: The detached promise call "void this.logModActionInChat(props)"
lacks a terminal catch; update the call site to append an explicit catch handler
(e.g., .catch(() => {})) so it follows the established detached-promise pattern
used elsewhere (see usage of this.shared.api.deleteMessage(...).catch(() =>
{})), keeping error handling explicit at the call site while preserving internal
error handling in logModActionInChat.
---
Nitpick comments:
In `@src/modules/tg-logger/index.ts`:
- Around line 532-537: The current promise chain conflates send and
delayed-delete failures into one catch, causing misleading logs; separate the
send and delete failure paths by handling the delete error locally: call the
send promise (the code using after(120_000) and the send that returns "sent"),
then in its .then attach a .catch on this.shared.api.deleteMessage(p.chat.id,
sent.message_id) to log a clear "Failed to delete moderation message" via
logger.warn (include { error, action: p.action }), and keep a top-level catch
only for the original send failure and log "Failed to post moderation action in
chat" (include { error, action: p.action }); reference the after helper, the
sent variable, this.shared.api.deleteMessage, and logger.warn to find where to
change the chain.
- Around line 532-533: The current post-send deletion chain uses an in-memory
timer (.then(after(120_000))) so a process restart can leave messages undeleted;
replace this best-effort timer with a small persistent cleanup queue: after
sending (where .then((sent) => this.shared.api.deleteMessage(p.chat.id,
sent.message_id)) is used) persist the tuple {chatId: p.chat.id, messageId:
sent.message_id, deleteAt: now+120s} to durable storage and have a background
worker/cron (or a restart-on-boot reconciler) that reads pending entries and
calls shared.api.deleteMessage(chatId, messageId) when deleteAt is reached and
removes the entry upon success, while keeping the original in-memory timer only
as an optimization.
🪄 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: CHILL
Plan: Pro
Run ID: f116044f-e680-4c13-a8b0-127208da5982
📒 Files selected for processing (1)
src/modules/tg-logger/index.ts
No description provided.