Skip to content

Fix Discord monitoring and Blood Moon alerts - #61

Open
El-Limon wants to merge 17 commits into
mainfrom
fix/discord-7d2d-monitoring-feedback
Open

El-Limon wants to merge 17 commits into
mainfrom
fix/discord-7d2d-monitoring-feedback

Conversation

@El-Limon

Copy link
Copy Markdown
Contributor

Summary

Fix Discord monitoring failures in discord-7d2d-status-bridge and make Blood Moon notifications reliable when Discord rejects delivery. The module now reports actionable authorization errors, checks phase transitions every minute, preserves unsent announcements for retry, and can privately warn the first player who joins on a Blood Moon day.

This addresses field feedback where chat relay worked but monitoring calls failed even after granting the game bot administrator rights. Discord delivery still requires the Takaro Discord integration to be authorized for the guild and channel.

Architecture

7D2D gettime
     |
     v
current installation config -> scoped monitor lock -> observed phase
                                                |-> pending announcements
                                                |-> delivered history
                                                `-> Discord send/retry

player-connected -> persisted observed phase -> online count == 1 -> private game message

What Changed

  • Discord diagnostics: Normalize 403/404/provider failures into safe, actionable guidance without exposing Axios request configuration or authorization headers. Persistent status messages are replaced only for Discord 10008 Unknown Message, not generic failures.
  • Blood Moon monitoring: Poll gettime every minute while leaving the heavier server-status update at five minutes. Daily intervals correctly represent the current Blood Moon day while also queuing the previous ending announcement.
  • Reliable delivery state: Separate observed, pending, and delivered state. Failed or skipped Discord sends remain pending across phase changes; legacy state migrates without duplicate announcements.
  • Concurrency and stale jobs: Serialize cron executions with an owner-checked renewable lock. Queued jobs refresh the current module installation after acquiring the lock, preventing old configuration snapshots from overwriting newer state.
  • Private first-player warning: Add an opt-in private Blood Moon message for the first online player, including English, Polish, and custom wording.
  • Integration coverage: Expand the real-Takaro suite for forbidden delivery, migration ordering, interval 1, retries, stale queued jobs, lock expiry/timeout, message localization, and first-player behavior.

Reviewer Guide

  • Start here: modules/discord-7d2d-status-bridge/src/cronjobs/blood-moon-monitor/index.js
  • Pay attention to: The durable write order is delivered migration -> observed phase -> pending queue -> Discord attempt.
  • Design decision: Delivery is at-least-once. If Discord accepts a message and the function dies before recording success, the next run may duplicate it; avoiding that would require a provider-side idempotency primitive.
  • Compatibility: A missing delivered-history variable is treated as the legacy module format, while new executions initialize it before changing observed state.

Testing Plan

Happy Path

  • Configure an authorized monitoring text channel and trigger bloodMoonMonitor; verify day/start/end messages arrive once.
  • Enable privateBloodMoonNoticeOnFirstJoin, join as the only player during today: or start:, and verify the private warning.
  • Set hordeIntervalDays to 1 after 04:00; verify the current state is today:<day> and ending/today announcements retain their order.

Edge Cases

  • Use a forbidden channel and verify the execution explains guild authorization plus View Channel, Send Messages, and Read Message History permissions.
  • Remove and reinstall the module while a cron is queued; verify the queued job uses the current installation config.
  • Remove the module while a cron is queued; verify it skips safely and releases its lock.

Regression Checks

  • Run npm run build and npm run typecheck.
  • Run the real-Takaro bridge integration suite in modules/discord-7d2d-status-bridge/test/bridge.test.ts.
  • Verify chat relay and the five-minute persistent status update still behave as before.

Verification Evidence

  • Build and typecheck pass.
  • Real Takaro suite exercised 43 cases; all Blood Moon, retry, migration, and concurrency cases passed. One unrelated event-search poll timed out once and passed on immediate isolated retry.
  • A real Paper bot triggered the player-connected hook and the private game-message route returned 200 OK.
  • Live 7D2D QA returned gettime, refreshed the current installation, persisted the expected daily-interval state, and released the monitor lock.
  • Available Discord QA channels currently return 403/404, so a live Discord 200 OK remains an environment/configuration gate rather than a code claim.

@El-Limon El-Limon added bug Something isn't working enhancement New feature or request labels Jul 24, 2026

@El-Limon El-Limon left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Self-review: three non-obvious reliability decisions worth checking closely.

const lockOwner = await acquireBloodMonitorLock(gameServerId, mod.moduleId);

try {
const installation = await getCurrentModuleInstallation(gameServerId, mod.moduleId);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Queued Takaro jobs contain an installation snapshot. Refreshing the current installation only after acquiring the lock prevents an older queued job from applying stale interval/channel configuration after a reinstall.

}
if (!sameHistory(storedDelivered, delivered)) {
await renewBloodMonitorLock(gameServerId, mod.moduleId, lockOwner);
await writeVariable(gameServerId, mod.moduleId, BLOOD_DELIVERED_KEY, delivered);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The write order here is intentional: migrate/initialize delivery history before replacing observed state, then persist pending work before Discord. This closes the crash window where an unsent current phase could be mistaken for legacy-delivered.

}
}

export async function acquireBloodMonitorLock(gameServerId, moduleId) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The variable-backed lock serializes scheduled/manual overlap. Ownership checks, lease renewal, bounded backoff, stale record-id reclamation, and owner-safe release are each covered through real Takaro integration cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant