Back to blog

Minecraft to Discord: What Happens When Notifications Fail?

Mineando
A grass and dirt block with a green envelope against a dark green background.

If Discord becomes unavailable, an announcement integration should leave the Minecraft event running, retain the notifications that still matter and make delivery problems visible to staff. Agree those behaviours before commissioning the plugin. A successful message during a demonstration does not establish what happens during an outage.

This guide covers one-way notifications from a Paper server to a Discord channel through an incoming webhook: registration summaries, round results or operational updates. It does not cover Discord commands that control Minecraft, account linking or role synchronisation. Those features need their own authority and identity rules. The design below is a proposed specification, not a tested Mineando implementation.

Decide which system owns the result

Suppose a tournament plugin records the end of a round and announces the winner in Discord. Make the stored tournament result authoritative. A missing announcement must not rerun the round, grant a reward again or change the winner.

Write two separate acceptance statements: “the round result has been saved” and “the announcement has been delivered”. Staff should be able to inspect both. Do not label a notification as delivered merely because it entered a queue.

For a modest integration, this separation is more useful than a long feature list. Add it to your plugin acceptance criteria and decide who may correct a result or resend its announcement. Resending must be a notification operation, never a replay of the underlying game action.

Give each notification a lifecycle

Ask for a stable event identifier, creation time, destination reference, expiry rule and delivery state. A practical state list is pending, delivered, expired and needs review. A retry should reuse the event identifier rather than create a new logical event.

For results that must survive a restart, request persistent storage. If the application stores results in a database, one possible design records the result and its pending notification in the same transaction. If that is not feasible, require a reconciliation process that finds saved results without notifications. The developer should explain and demonstrate the selected design; a memory-only queue does not meet a persistence requirement.

Keep this work separate from the server tick. Paper advises moving slow network work off the main thread and warns that world access from asynchronous tasks can be unsafe. The implementation must respect both boundaries. See the Paper scheduling documentation.

Moving work to another thread also needs limits. Specify a maximum backlog and what happens when it fills. For this tournament example, keep official results available in the authoritative store, flag the notification failure and let staff reconcile it. Do not silently overwrite an important pending result to make room for routine status messages.

Separate delays from broken configuration

Discord instructs clients to read rate-limit responses dynamically. For HTTP 429, follow Retry-After or retry_after; do not bake in a universal sending quota. A webhook returning 404 should stop being retried. These rules come from Discord's rate-limit documentation.

For temporary network failures, agree a bounded retry policy with increasing delays and some random variation. Specify both the attempt limit and the maximum message age. When either is reached, move the notification to review or expiry according to its purpose. An endless retry loop is not an operating procedure.

Broken credentials, invalid payloads and unavailable destinations need a staff-visible diagnosis. The handover should say which failures pause the destination and how an operator resumes it after correction. Keep useful identifiers and error categories in logs; exclude webhook secrets. Test environments must use separate destinations so rehearsals cannot post to a live community channel.

Be honest about duplicate delivery

For stronger delivery confirmation, Discord's webhook API offers wait=true, which returns the created message. Store its identifier when available. This is documented under Execute Webhook.

Even then, consider this sequence: Discord accepts a message, but the connection breaks before your application receives the response. The application cannot safely infer that nothing was posted. A retry may produce a second announcement. Recording an internal event identifier helps investigation; putting that identifier in a message does not make the destination deduplicate it automatically.

Agree a policy for this ambiguous case. A routine result notice might tolerate a clearly recognisable duplicate. A high-impact announcement might instead wait for staff review before another send. Neither policy should repeat the game result or its rewards. Avoid accepting “exactly once” as a promise without a demonstrated mechanism and clearly defined failure boundaries.

Decide what should expire

An outage can leave perfectly valid messages that are no longer useful. “The next round starts in two minutes” should not appear after that round has finished. In contrast, an official result may still be worth delivering later with its original event time.

Use a small policy table in the specification:

NotificationProposed recovery behaviour
Round starting soonExpire when the relevant round starts.
Official round resultRetain for review or delayed delivery with its original time.
Repeated server status updateReplace older pending status with the latest, if history is not required.

These are editorial examples, not Discord defaults. Choose the policies with the event producer. Preserve ordering where it matters, and decide whether a later result can overtake an earlier failed notification. After recovery, drain the queue deliberately instead of flooding the channel with an unexplained backlog.

Rehearse the failures before handover

Use an isolated test server and a controlled test destination or simulated HTTP service. Do not deliberately overload Discord to trigger its limits. Ask the developer to run these cases and attach evidence:

  1. Delay the destination response: gameplay continues and the notification stays pending.
  2. Simulate a rate-limit response: the next attempt respects the supplied delay.
  3. Restart with pending results: the agreed records survive and processing resumes.
  4. Simulate acceptance followed by a lost response: the ambiguous-delivery policy is visible.
  5. Remove the test destination: retries stop and staff see a repairable failure.
  6. Recover after a round has started: its expired countdown is not announced.
  7. Fill the agreed backlog: the documented overflow behaviour occurs without replaying game actions.

Record release versions, inputs, expected and actual outcomes, queue state and timestamps. Leave results marked “not run” until somebody executes the tests. Measure server behaviour during the agreed scenario; this checklist supplies no player-capacity benchmark.

For an event rehearsal, assign someone to watch pending count, oldest pending age and unresolved failures. Provide an escalation route outside the failed notification path. Agree who can pause sending, reconcile uncertain deliveries and approve a resend.

If you need a custom Minecraft integration, bring the event types, destination, expected bursts, expiry policies and failure checklist to the project discussion. Mineando scopes and quotes paid development individually. Maintenance and live coverage need a separate agreement.

Tell us what you’re building.

Paid projects, with a scope and quote agreed before we start.

Discuss your project