TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Reliable event dispatching using a transactional outbox

31 pointsby losfairover 2 years ago

5 comments

kgeistover 2 years ago
Oh, it took us around 2 years to have somewhat reliable event dispatching with transactional outboxes. We&#x27;ve run into so many edge cases under highload:<p>- using the autoincrement ID as a pointer to the &quot;last processed event&quot; not knowing that MySQL reserves IDs non-atomically with inserts so it&#x27;s possible for the relay to &quot;see&quot; an event with a bigger ID before an event with a smaller ID becomes visible, thus skipping some events<p>- implementing event handlers with &quot;only once&quot; semantics instead of &quot;at least once&quot; (retries on error corrupting data)<p>- event queue processing completely halting for the entire application when an event handler throws an error due to a bug and so gets retried infinitely<p>- some other race conditions in the implementation when the order of events gets messed up<p>- too fine-grained events without batching overflowing the queue (takes too much time for an event to get processed)<p>- the relay getting OOMs due to excessive batching<p>- once we had a funny bug when code which updated the last processed ID of the current DB shard (each client has their own shard) wrote to the wrong shards and so our relay started replaying thousands events from years ago<p>- some event handlers always sending mail as part of processing events, so when it&#x27;s retried on error or replayed (see the bug above) clients receive same emails multiple times<p>And still we have sometimes weird bugs like once a month for some reason we see a random event getting replayed in a deleted account, still tracking it down.
评论 #34658567 未加载
svieiraover 2 years ago
This is interesting, but you&#x27;ve not actually solved the problem, just moved it. You still need cross-service transactions to publish the event only-once. Consider the case of &quot;Publish the event to the queue. Fail to update &#x2F; delete the entry in the event-buffer table.&quot; This is the &quot;bad&quot; pattern of push-then-store (with one exception - if you are fine with at-least-once message delivery instead of only-once). Likewise the &quot;good&quot; pattern of store-then-push has the same failure mode &quot;Delete the entry from the buffer. Fail to publish the entry to the queue&quot;.<p>That said, this does decouple the two operations which allows you to scale the publish side of the service separately from produce side (which can help when your architecture can produce multiple messages per storage event)
评论 #34658427 未加载
评论 #34656464 未加载
评论 #34656389 未加载
评论 #34656447 未加载
chuckeover 2 years ago
On the topic, I created this ruby gem called tobox, essentially a transactional outbox framework: <a href="https:&#x2F;&#x2F;gitlab.com&#x2F;os85&#x2F;tobox" rel="nofollow">https:&#x2F;&#x2F;gitlab.com&#x2F;os85&#x2F;tobox</a><p>It actually circumvents most of the limitations mentioned in the article. Been successfully using it at work as an sns relay, for another app which is not even ruby.
groodtover 2 years ago
Any thoughts how to detect direct DML on the state table? Presumably allowing direct DML on the state table without the same on the Outbox table would lead to silent data corruption or lost updates.
mkleczekover 2 years ago
I must say not mentioning two phase commit and distributed transactions in this context seems strange.<p>It looks like nowadays people forgot about XA and that MQ and DBMS can participate in a distributed transaction.
评论 #34658680 未加载