简体   繁体   English

如何避免pub / sub反映事件?

[英]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. 这是一个基本的反映(以我的观点),可以通过简单地忽略集线器上来自同一ds(数据源)的相同事件,直到完成当前事件处理过程来避免。 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. 通过同步代码,我们可以简单地用事务覆盖该过程,并检查当前ds是否已经同步。 If yes then ignore it. 如果是,则忽略它。 What if we have 2 hubs synchronizing the same 2 data sources: 如果我们有2个集线器同步相同的2个数据源怎么办:

-> 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. 将事务ID添加到事件中并且永不结束事务将导致内存泄漏。 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. 因此,我决定接受TJ Crowder的回答,因为比较值而不是创建全局事务对象是一个天才的想法。 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. 我在这里问了同样的问题: https : //softwareengineering.stackexchange.com/questions/241599/how-to-a-void-oscillation-by-async-event-based-systems ,我在那里有一个关于如何防止状态振荡。

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. 基本上,订户需要有一个未决事件的FIFO队列。

Suppose A subscribes to change events for x from B , and B subscribes to change events for x from A . 假设A预订了B x更改事件,而B预订了A x更改事件。 Then something changes Ax : 然后事情改变了Ax

  1. A sees the x value changed, saves the new value, and raises a change. A看到x值已更改,保存新值并引发更改。
  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. BA看事件,将事件x与它自己的x进行比较,看它们是否不同,保存并提出更改。
  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. A看到来自B的change事件,将事件中的x与它自己的x进行比较,发现它们相同,并且什么也不做。

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. 如果不能保证,那么您将遇到以下问题: A可能引发将x更改为1的事件,然后引发另一个将x更改为2事件,并且如果Bx=>2之前发现x=>2发生了更改x=>1变化, AB可能会以无休止的循环结束。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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