简体   繁体   中英

How to avoid event reflection by pub/sub?

I want to keep various data sources in sync. To do that I want to broadcast change events using an event hub. So in this structure every data source can be a publisher and a subscriber of events either. Currently I don't have an implementation, I am just thinking on how to do that.

I have problem to figure out how to prevent event reflection (infinite loop in other terms). So by a data source

-> ds.change -> hub.publish(ds, event) -> hub.subscriber[x] = ds.sync(event)
-> ds.change -> ... //infinite loop caused by sync triggered change event

This is a basic reflection (in my terms), this can be avoided by simply ignoring the same events from the same ds (data source) on the hub until the current event handling process is done. But how should we know when it is done?

By sync code we can simply cover the process with a transaction and check if the current ds is already synchronized or not. If yes then ignore it. What if we have 2 hubs synchronizing the same 2 data sources:

-> ds.change -> hub1.publish(ds, event) -> hub.subscriber[x] = ds2.sync(event)
-> ds2.change -> hub2.publish(ds2, event2) -> hub2.subscriber[x] = ds.sync(event2)
-> ds.change -> ... //infinite loop caused by signal sent back by the other hub

So we have to cover the 2 hubs with the same transaction. So we have to use some sort of global transaction.

Now all of these can be solved more or less with a sync code. But what about an async code? How can I end a transaction if I cannot determine exactly when I should do that? Ending a transaction too early or too late would cause an invalid application state. Adding a transaction id to the events and never ending the transaction would cause a memory leak. Any idea?

Conclusion

The async part of the problem is very hard and it is more about concurrent threads, thread safety and parallel programming then simple event handling. So I decided to accept TJ Crowder's answer, because it is a genius idea to compare the values instead of creating a global transaction object. If you have a general solution for the async part of the problem, please share it with us!

I asked the same question on here: https://softwareengineering.stackexchange.com/questions/241599/how-to-avoid-oscillation-by-async-event-based-systems and I got there a more general answer about how to prevent state oscillations.

If a publisher only raises an event when something changes , you'll avoid infinite loops if you can be guaranteed that subscribers receive earlier events before receiving later events. You can ensure that guarantee with either synchronous or asynchronous event dispatch; in the latter case, it's more work, because subscribers have to acknowledge having received an event before you give them the next one. Basically subscribers need to have a FIFO queue of pending events.

Suppose A subscribes to change events for x from B , and B subscribes to change events for x from A . Then something changes Ax :

  1. A sees the x value changed, saves the new value, and raises a change.
  2. B sees the event from A , compares the x on the event with its own, sees they're different, saves it, and raises a change.
  3. A sees the change event from B , compares the x on the event with its own, sees they're the same, and doesn't do anything.

If you can't have that guarantee, then you run into the problem you describe below: A could raise an event changing x to 1 , then raise another event changing x to 2 , and if B sees the x=>2 change prior to the x=>1 change, A and B could end up in a never-ending cycle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM