事件驱动架构...无限循环

16

我有一个事件驱动的架构,其中A正在等待来自B的更改,B正在等待来自C的更改,而C正在等待来自A的更改,形成一个循环。

现在,如果B发生更改,则A向C触发事件,C触发到B,B触发到A,A触发到C...以此类推。

我现在可以更改我的程序,使其不包含这个循环,但我担心以后可能会陷入一个无法摆脱的困境。在设计基于事件的系统时,如何避免这种情况的发生?


1
听起来像是递归...你需要一个守卫条款/基本情况来停止事件。 - Oded
很有趣,我也遇到了同样的问题。最终我们不得不重构那部分代码。 - Chuck Conway
这似乎是应用有限状态机的完美场景。 - Eric Schnipke
5个回答

8
每个人都认为循环依赖是不好的。在某种程度上,这是正确的,我尽量避免静态循环依赖。您可以通过控制反转来实现,就像这篇博客中所概述的那样:http://blog.schauderhaft.de/2011/07/17/breaking-dependency-cylces/ 但是你描述的并不一定是静态循环依赖,而是运行时的循环依赖。我不完全确定,但我认为几乎不可能避免运行时的循环依赖。但是当然,这不应该导致无限循环。要解决这些问题,我看到两种半个选项
第一个方法:
确保由其他事件触发的每个事件都引用原始事件(或其关键信息,例如ID)。每当处理事件时,请确保它不是自己发起的。
优点:易于实现;绝对防止递归
另一种方法:
如果您正在同步运行,则可以在之前设置标志firingEvent,并在之后重置它。在设置了firingEvent的情况下忽略传入的事件。
优点:更容易实现;在单个线程中运行时绝对防止递归
语义丰富的解决方案:
我相信A在某些外部触发器上触发的事件和A因C而触发的事件实际上是两个不同的事件,或者所有三个事件实际上只是来自尚未确定的源D的一个事件。之类的。没有办法在没有关于A、B和C以及它们正在触发的事件的信息的情况下进行判断。如果找到正确的事件,循环将消失。
优点:设计将更加清晰,并包含更多信息。

2
当设计基于事件的系统时,如何避免这种情况发生呢?
  1. 仅在对象状态真正更改时引发事件。

  2. 在引发事件时禁止对象状态更改。


2

绘制出你的依赖关系图,不应该有循环。循环依赖是重新组织代码的好借口。

它们还可能导致死锁,如果你需要另一个原因来避免它们的话。


1
是的,但如果您的事件驱动系统不包含在单个服务中怎么办呢?例如,如果您正在运行一个微服务架构,其中每个服务都拥有自己的数据,并且您正在利用事件源来在上下文/服务之间保持相关数据同步。您并不一定知道可能导致循环的每种处理程序组合。 - Sinaesthetic

0

我认为这是一个好问题。不幸的是,我自己没有完整的答案,但是这篇文章提出了一些好观点:

如何避免观察者模式中的无限循环?

我不认为答案是避免循环依赖,正如其他人所建议的那样。(好吧,这取决于你对“循环依赖”的定义。)像Java这样的语言会使用接口来在编译时最小化类型之间的循环依赖,这通常是一个好主意。例如,在MVC模式中的视图类不“依赖”于您的应用程序,它只知道名称为ValueChangedListenerClickListener等的接口。但这并不能消除运行时对象之间的循环连接,这就是可能导致事件循环的原因。

如在其他链接的帖子中提到的那样,一些循环在 UI 工具包中停止,因为如果控制器或模型“设置”视图的值为与其当前值相等的值,则视图不会触发“更改”事件。但在其他情况下,例如当您创建更复杂的数据的自定义视图时,计算当前数据和新数据的相等性可能是不可行的。

-3

循环依赖关系是真的不好。在我理解你的帖子之前,我必须按照A、B和C的术语写下来。我认为你应该摆脱它。如果你把自己逼入一个死角,那么这可能比循环依赖关系带来的问题要好得多。

你肯定也可以避免这种情况。A、B和C之间紧密耦合。我认为你需要重新思考它们的职责。也许有一个共同的D元素会减轻你的设计压力。

另一个想到的方案是架构分层。如果你能将A层放在B层上,并要求任何与B交流的人都必须通过A并沿着各层进行通信,那么你可能会更容易一些。再次强调,我对你的问题了解不多,所以这些只是广泛的建议。

最后一个选择,也是我最不喜欢的,是在三个组件之间传递消息。当访问每个组件时,要求每个组件添加已接收到消息的信息。然后下一个接收消息的组件就会知道谁已经看到了消息。有点像签到表。但是再次强调,最好先尝试其他方法。

祝你好运!


2
我认为他所说的不是循环依赖,而是事件循环。A、B和C正在监听事件,假设代码通过观察者模式完全解耦。问题似乎在于他编写的代码使得一个组件的更改会传播到另一个组件。这与代码耦合无关。 - Daniel Cerecedo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接