Duplicate POST requests on retry cause unintended data creation
29K reputation · 12 May 2021, 07:38 UTC
The goal is to configure retry logic for create/update operations (POST/PUT/PATCH) that feed an Angular Material MatTable so that transient server errors are retried without causing duplicate records. The solution must keep the mat‑progress‑spinner visible during retries, avoid altering the original user‑initiated payload, and work with the existing CDK Directionality and Portal services.
Uncertainty remains about where to place the retryWhen operator relative to shareReplay or similar multicasting operators so that a failed attempt does not get cached and subsequent retries actually re‑send the HTTP call. Additionally, it is unclear how to generate and attach an idempotency key automatically within the data‑source stream without exposing the key to the UI or requiring manual handling in each component. Finally, developers wonder whether using a MatSnackBar action to trigger a retry can guarantee that the exact same request body is retried, or whether extra safeguards are needed to prevent duplicate writes. What is the recommended placement of retryWhen relative to shareReplay to ensure retries re‑execute the call? How can an idempotency key be added automatically to the request stream without UI exposure? Does a MatSnackBar‑triggered retry guarantee identical payloads, or must additional client‑side deduplication be applied?
1 answer
1 question comment
Use comments to ask for clarification. Post a solution as an answer.
29,025 reputation · 12 May 2021, 16:27 UTC
When using shareReplay for loading state, add resetOnError: true (RxJS 7+) so that a failed HTTP response is not cached; otherwise the error would be replayed on subsequent subscriptions and retryWhen would never re‑execute the call. Place the idempotency‑key injection (via map or an interceptor) before retryWhen, then shareReplay(1, { refCount: true, resetOnError: true }) after the retry logic. This order guarantees each retry issues a fresh POST with the same key, while the MatTable and spinner stay subscribed to the latest execution. A MatSnackBar action that simply re‑invokes the same request‑factory function will resend the identical payload, provided the factory does not depend on mutable component state; otherwise extract the payload into a pure constant or service method to guarantee consistency.