Skip to content

send_sms: stop a retry from sending the SMS twice - #2

Open
aurumflux20 wants to merge 1 commit into
DevsJony:masterfrom
aurumflux20:send-guard
Open

send_sms: stop a retry from sending the SMS twice#2
aurumflux20 wants to merge 1 commit into
DevsJony:masterfrom
aurumflux20:send-guard

Conversation

@aurumflux20

Copy link
Copy Markdown

Closes the issue I opened in #1, with the client-side guard rather than the fix I first suggested there.

Why not the fix from the issue

In #1 I suggested making transactionId deterministic so the API would collapse a retry. Your README says that won't worktransactionId generuje serwer (UUID) - API go nie nadaje — the API neither assigns nor interprets that field, so there's no basis to assume it deduplicates on it. My original suggestion was wrong and this PR does the other thing: the guard lives in this server.

The change

send_sms now takes an optional transactionId, and derives one from the shipment itself when the caller doesn't supply it. A shipment already sent within SMSON_DEDUP_TTL_MS (default 15 minutes) returns its original result instead of going out again.

Two details that matter more than the dedup itself:

  • A genuinely different message still sends. The derived key covers the whole shipment, so changing the number, the text, the sender or the schedule produces a different key. A guard that collapsed distinct messages would be worse than the bug.
  • A FAILED send is not remembered, so a transient failure stays retryable rather than becoming permanently un-sendable.

Scope, honestly

The record is in-memory. It covers a retry within one running server — an agent re-dispatching seconds later, which is the case people actually hit — and not a restart between the send and the retry. A durable store would close that too; this is the smallest change that fixes the common failure, with no new dependency.

Tests

test-dedup.mjs starts the real server over stdio against a local stand-in for the API, so it exercises the actual tool handler:

PASS  first send reaches the API
PASS  an identical retry does NOT send again
PASS  the retry returns the original result
PASS  a genuinely different message DOES send
PASS  a caller-supplied key is honoured
PASS  ...and repeating it does not resend
PASS  a FAILED send stays retryable

node test-dedup.mjs — no credentials needed, exits non-zero on failure.

Disclosure

Same as in #1: I maintain open-source exactly-once tooling, so I have a commercial interest in this class of bug. Deliberately no dependency on any of it here — this is ~40 lines of your own code. Take it, change it, or close it; flagging it either way.

transactionId was minted with randomUUID() on every call, so two calls
describing the same shipment looked like two different shipments. An agent that
retries after a timeout -- the response was lost, the SMS already went -- sends
the message again.

Making transactionId deterministic is not enough on its own: the README is
explicit that the API neither assigns nor interprets that field
("transactionId generuje serwer (UUID) - API go nie nadaje"), so there is no
basis to assume it deduplicates on it. The guard has to live in this server.

send_sms now takes an optional transactionId, and derives one from the shipment
when the caller does not supply it, so an identical resend collapses while a
genuinely different message is unaffected. A shipment already sent within
SMSON_DEDUP_TTL_MS (default 15 min) returns its original result instead of
being sent again. A FAILED send is deliberately not remembered, so a transient
failure stays retryable.

Scope stated honestly: the record is in-memory, so it covers a retry within one
running server and not a restart. That is the case people actually hit; a
durable store would close the rest.

test-dedup.mjs drives the real server over stdio against a local stand-in for
the API and asserts all seven behaviours, including that a different message
still sends and that a failure stays retryable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant