feat: add opt-in idempotent webhook recovery and restart tests - #886
Draft
Tsubashimo-Nanato wants to merge 2 commits into
Draft
Tsubashimo-Nanato wants to merge 2 commits into
Tsubashimo-Nanato wants to merge 2 commits into
Conversation
|
@Tsubashimo-Nanato Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
When a scheduled webhook is accepted but the sender exits before recording COMPLETED, lease recovery sends it again. This adds persisted restart tests and an opt-in idempotency contract for cooperating webhook receivers: retries reuse a UUID committed in SQLite before the first send, allowing the receiver to avoid repeating its business effect.
Draft: acceptance scope and upstream prerequisites still need agreement. This does not make arbitrary webhook endpoints, Discord, email or SMS exactly-once. The option is disabled by default and is not automatically enabled by the application.
Related Issue
Closes #795
Linked for Wave tracking; this remains a draft pending agreement on the receiver contract and verification gates. The Wave deadline is September 30, 13:00 UTC (22:00 JST).
Two reviewable scopes are preserved in separate commits:
1043d51: seven persisted restart tests, with the post-HTTP-success crash gap explicitly left open.34dd996: A plus the opt-in implementation, receiver contract and crash test below.Please confirm whether B's conditional guarantee is the intended scope, or whether A should land with the crash gap tracked separately. The earlier scope discussion has the reproduction context.
Changes
Idempotency-Key; a fixed shared header is rejected in opted-in mode.src.docs/WEBHOOK_IDEMPOTENCY.md.The receiver must atomically commit its business effect and receipt, replay the stored success for the same request, reject conflicting content, and retain keys for every possible retry. All workers must keep the same provider policy. Old unkeyed in-flight jobs must be drained/reconciled before enabling it; mixed destinations need an agreed routing policy. There is no finite retry-lifetime guarantee for safe receipt expiry.
Verification
Node 22.23.3/npm 10.9.9, from
listener/:npm test -- --runInBand --detectOpenHandles --runTestsByPath src/__tests__/scheduler-restart.integration.test.ts src/__tests__/delivery-idempotency.integration.test.ts src/__tests__/scheduler-idempotency-crash.integration.test.ts src/services/retry-scheduler.test.tsindex.ts,security-headers.tsanddiscord-notification.ts; lint invokes the same compiler. No full-suite, build or CI success is claimed.How to Test
Current main (
30b99fe) cannot completenpm ci: its lockfile disagrees with the manifest. Local validation used a lockfile sync to the existing manifest and the three-linerequest-id.tsrepair from #846. Those prerequisite repairs are excluded from this PR. Resolve them before running the focused command; the tests need no live service credentials.Provider setup and receiver acceptance steps are in the linked contract document. Production activation is intentionally a separate decision.
Checklist
main(30b99fe, checked September 29).cargo fmt --allrun — not applicable; no Rust changes.npm run lintpasses — existing compiler errors remain.