Skip to content

fix: delete mod action logs in chat after 2 mins#84

Merged
toto04 merged 3 commits intomainfrom
fix-2min-log
Apr 11, 2026
Merged

fix: delete mod action logs in chat after 2 mins#84
toto04 merged 3 commits intomainfrom
fix-2min-log

Conversation

@toto04
Copy link
Copy Markdown
Contributor

@toto04 toto04 commented Apr 11, 2026

No description provided.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 11, 2026

Walkthrough

Made moderation logging fire-and-forget and added a timed cleanup: moderationAction now calls logModActionInChat(props) without awaiting, and logModActionInChat sends the message, waits 120000 ms, then deletes the sent message. Also added after(time_ms) utility to compose delays in promise chains.

Changes

Cohort / File(s) Summary
New Delay Utility
src/utils/wait.ts
Added exported after(time_ms) which returns a generic function <T>(value: T) => Promise<T> that awaits the specified duration (via existing wait) and resolves with the original value, enabling delays in promise chains.
Moderation Logger Integration
src/modules/tg-logger/index.ts
Changed moderationAction to invoke logModActionInChat(props) in a fire-and-forget manner (void call). In logModActionInChat, after sendMessage(...) the code now chains after(120_000) then calls deleteMessage(p.chat.id, sent.message_id), preserving existing .catch(...) warnings.

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
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: deleting moderation action logs from chat after a 2-minute delay.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 | 🟠 Major

Avoid blocking this method for 120 seconds.

Because logModActionInChat is awaited by moderationAction, 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

📥 Commits

Reviewing files that changed from the base of the PR and between b25e1de and 9c9922c.

📒 Files selected for processing (2)
  • src/modules/tg-logger/index.ts
  • src/utils/wait.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 9c9922c and c52986c.

📒 Files selected for processing (1)
  • src/modules/tg-logger/index.ts

@toto04 toto04 merged commit 6f9b761 into main Apr 11, 2026
2 checks passed
@toto04 toto04 deleted the fix-2min-log branch April 11, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants