Make reaction ingest atomic#1458
Merged
Merged
Conversation
Collapse kind:7 reaction ingestion into one database transaction so reaction rows, event rows, and thread metadata commit or roll back together. Preserve duplicate short-circuit and soft-delete reactivation semantics by sharing the existing reaction upsert SQL between pool and transaction paths. Co-authored-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co> Signed-off-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co> Signed-off-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
7a08f14 to
9468315
Compare
wpfleger96
added a commit
that referenced
this pull request
Jul 2, 2026
…n-metrics * origin/main: feat: per-community workspace icon set by admins, served via NIP-11 (#1463) perf(relay): batch outbound websocket data frames (#1464) Make reaction ingest atomic (#1458) Serialize fan-out EVENT frames once (#1459) fix: agent reliability — no restart on channel-add, visible dead-letter notice (#1468) Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com> # Conflicts: # crates/buzz-relay/src/handlers/event.rs
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.
Summary
Make kind:7 reaction ingestion atomic by moving the reaction row upsert, kind:7 event insert, and optional thread metadata insert into one
buzz-dbtransaction.This removes the previous relay-level multi-query/compensation sequence:
New path:
Changed files
crates/buzz-db/src/event.rsReactionEventInsertOutcome.insert_event_with_thread_metadatainto an internal tx-taking helper.insert_reaction_event_with_thread_metadata.crates/buzz-db/src/reaction.rsADD_REACTION_SQLbetween pool and tx paths.add_reaction_txpreserving existing reactivation / duplicate semantics.crates/buzz-db/src/lib.rscrates/buzz-relay/src/handlers/ingest.rsQuinn §4.14 fence table
P4 diff verified against
RESEARCH/RELAY_PERF_CORRECTNESS.md§4.14. All six fences hold in code:insert_reaction_event_with_thread_metadatabody reads exactly: target SELECT →add_reaction_tx→!reaction_insertedshort-circuits withtx.rollback()returningDuplicate→ event insert only after that check. If ordering ever flipped, a duplicate reaction would store a duplicate kind:7. This diff preserves the guarantee.SELECT ... WHERE community_id=$1 AND id=$2 AND deleted_at IS NULL ORDER BY created_at DESC LIMIT 1. Explicit.Inv_NonInterference— cross-community A→B target attack returnsTargetMissingand the test proves it (reaction_single_tx_cross_community_target_rejectedasserts both no event AND no reaction row).tx.rollback()/tx.commit()is the only exit surface.e-tag extraction, 64-char emoji cap, empty-content+default,effective_message_authorderivation — all preserved iningest.rs. DB helper is pure plumbing.insert_mentionsfires post-commit outside the tx via&self.pool, best-effort withwarn!on error — matches the existing non-reaction pattern. Zero cross-contamination.ADD_REACTION_SQLis oneconststring, used by bothadd_reaction(pool) andadd_reaction_tx(tx). Same bind order, same.execute()-then-rows_affected() != 0shape. Zero SQL divergence risk. TheCOALESCE(EXCLUDED.reaction_event_id, reactions.reaction_event_id)clause is the exact behavior Quinn named — new gets set, reactivate preserves an existing id, active-duplicate returnsfalse.Tests
Run at exact rebased SHA
0d4980c857d0caab558dcf5424162263fe132491after rebasing onto merged main9967b97f:Results:
cargo fmt --checkpassed.cargo test -p buzz-db: 79 passed, 53 ignored.cargo test -p buzz-relay: 448 passed, 2 ignored; main test 1 passed; doc tests passed.Required PG-gated tests present:
reaction_single_tx_duplicate_short_circuit_stores_no_eventreaction_single_tx_cross_community_target_rejectedreaction_single_tx_event_insert_failure_rolls_back_reactionreaction_single_tx_reactivates_soft_deleted_reaction