Preventing Duplicate Password-Reset Notifications (Under SMS Timeout and Retry Pressure)

2026年8月17日4 次浏览来源:Dev.to阅读原文

Treat an SMS timeout as an unknown outcome, not a failed send: accept each password-reset event once, persist its expiry and idempotency key before dispatch, and retry only through a worker that can reconcile the original attempt.

For a short-lived e-commerce reset token, compliance evidence is the deciding constraint.

The system must be able to show what it accepted, what it attempted, when it stopped, and why, without storing the token or message body in an audit log.

This changes the shape of the endpoint.

A Node.js Express handler may receive the event, but it shouldn't hold the HTTP request open while an SMS provider decides the final delivery state.

Return an accepted response after durable admission, then expose status from local state.

The Go example below shows the same transport-independent contract because the hard part isn't an Express API call; it's controlling ownership of retries.

One event, one logical notification.

How should event notifications handle SMS timeout, retry, and duplicate sends?

Use two identifiers with different jobs. identifies the business action, such as one password-reset request. identifies the logical notification command.

A unique constraint on the key makes two concurrent HTTP requests converge on one stored record; checking memory before an insert is not enough because two processes can pass that check together.

A timeout leaves three possible realities: the provider never accepted the request, it accepted the request but the response was lost, or it accepted and sent the message before the caller stopped waiting.

Retrying immediately as though the first case were certain is how customers receive two reset messages.

Declaring success is no better.

The durable record should therefore enter , keep the provider's attempt identifier when one exists, and move through reconciliation before another send can be authorized.

Status polling serves a different purpose from retry.

Polling reads the provider's view and updates the local record; it must not create a second message.

That separation is small on a diagram and easy to blur in code — especially when a generic function owns both operations.

Don't combine them.

The expiry is also a dispatch boundary, not presentation metadata.

Before every attempt, compare the current time with .

Once the reset token is too close to expiry for a useful delivery, mark the notification and stop.

The exact safety margin depends on observed queue and carrier delay, so I'm not sure a universal number would be defensible; resolve it from your own latency distribution and product policy, then record the chosen margin as configuration that can be audited.

The delivery contract and failure states The useful contract is narrower than “send this string.” It says: admit a password-reset notification exactly once for a stable event identifier, never dispatch it after expiry, retain evidence of each state transition, and let callers inspect the logical result without triggering work. “Exactly once” here describes admission of the logical command.

It does not pretend that an external SMS network participates in the same database transaction.

Local state Meaning Permitted next action The event and expiry are durably stored One worker may claim it A lease-holder owns the current attempt Wait or reclaim an expired lease The request outcome is ambiguous Reconcile status; do not blindly resend The provider accepted the logical message Poll status or finish Delivery evidence was observed Finish A classified permanent failure occurred Finish and surface a safe user action The reset window closed Finish; require a new reset request Every transition needs a timestamp, old and new state, event ID, attempt number, and a reason code.

Keep credentials, the reset URL, the token, and the full phone number out of those records.

A redacted destination fingerprint can support correlation, but access to it still belongs under the same retention and authorization controls as the rest of the e

分享
Baike.dev

baike.dev helps you discover great languages, frameworks, databases, DevOps and cloud-native tools.

Quick links

About

Contribute

Found a great developer tool? Share it with the community.

Submit a tool
© 2026 baike.dev Developer EncyclopediaUpdated daily · Discover great developer tools