Confirm publishes against the relay's OK, not the send queue #56
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Split out of #55 rather than bolted onto it. (Checked the tracker first — #35 raises "consider returning a success boolean", which #55 did, but nothing covers the OK frame itself.)
NostrClient.publish_nostr_eventreturns as soon as the req is on the queue:publish_event_to_nostrlogsPublished NIP-52 calendar eventon the next line, and after #55 that's also wherenostr_publish_pendinggets cleared. So "published" means "queued", and a relay that never receives the event — or receives it and rejects it — looks identical to success.is_websocket_connectedreadsself.ws.keep_running, which stays True on a socket that's dead but not yet noticed, so bytes can be accepted and dropped with nothing raised. #55's hold-and-retry only covers the case wherews.sendactually raises.What it needs
["OK", <event_id>, <true|false>, <message>]frames off the receive side and correlate them to in-flight publishes by event id.publish_nostr_eventawaits that correlation with a timeout, returning success/failure.nostr_publish_pendingonly on an OK true; a false or a timeout leaves the row flagged, and the #55 sweep retries it.created_ator a size limit.The receive loop already exists (
get_event/receive_event_queue), so this is mostly correlation bookkeeping rather than new plumbing.Priority
Low-ish. Neither production incident (#35 on aio-demo, #51 on cfaun) went through this gap — both failed or were skipped before anything reached the queue, and #55 covers those. This closes the last silent path rather than a known-live one.
Worth noting the same gap exists in every extension using this NostrClient pattern (it came from nostrmarket), so a fix here is a candidate to carry over.
This gap hit production today — correcting the priority note
I closed this issue saying "neither production incident went through this gap… this closes the last silent path rather than a known-live one." That's now wrong. It bit within an hour of #55 deploying, and it silently reverted a completed repair.
What happened
Context: the cfaun signer for
Q6mhQQzQPSXqkQuFndzXnfhad just been restored (see aiolabs/lnbits#73), so the #55 sweep should have republished the event and corrected a 14-day-stale ticket count. Journal times are CEST:51fee6d0…never reached the relay. Querying the relay for everything that author ever published returned five events, newest still the Sep 12 one:The publish landed 21 seconds before nostrclient had a connected upstream relay, so
NostrRouter._handle_client_eventtook its short-circuit:The router said
OK falseand told us exactly what was wrong. We threw it away, loggedPublished, clearednostr_publish_pending, and counted1/1 recovered.Why that's worse than the original bug
Before #55, drift was invisible. After #55, drift is visible and self-healing — except here, where the sweep marked the row clean on a delivery that never happened. The row would never be retried; the count stayed stale; and the log positively asserted success. A manual
was needed, after which the next sweep published for real (
created_at 1790502680,avail=45 sold=5).So the flag's contract — "cleared only on a confirmed success" — isn't actually honoured today. It's cleared on a confirmed enqueue. Reading the OK is what makes the contract true, which makes this a correctness dependency of #55 rather than a nice-to-have after it.
The good news for implementing it
nostrclient already does the hard part.
NostrRouter._handle_command_resultsaggregates per-relay results into exactly one NIP-01OKper published event id —trueas soon as any relay accepts,falseonce all reject or afterPUBLISH_TIMEOUT_SECONDS(10s), and it carries the relay's message. So this is correlation bookkeeping in our client, not new protocol work, and the failure messages are already meaningful ("error: no relays connected"would have named this instantly).Related but secondary
REPUBLISH_SWEEP_FIRST_DELAY = 60races nostrclient's relay connection — boot to relay-connected was 81s here, andcheck_relaysonly retries every 20s so the window varies. Raising the delay would have hidden today's failure rather than fixed it: a relay can drop at any time, not only at boot. Worth a small bump anyway for the common case, but it isn't the fix.