16

I have an event driven architecture where A is waiting for a change from B and B is waiting for a change from C and C is waiting for a change from A, forming a cycle.

Now, if B changes, then A fires an event to C, which fires to B, which fires to A, which fires to C...ad infinitum.

I can change my program right now to not contain this cycle, but I am concerned I may put myself into a corner at a later time where I cannot. How does one keep such things from happening when designing event based systems?

Bain Markev
  • 2,935
  • 5
  • 29
  • 28

5 Answers5

7

Everybody here seems to say that cyclic dependencies are bad. This correct in a sense and I try to avoid static cyclic dependencies at almost all costs. You can do so with inversion of control as sketched in this blog: http://blog.schauderhaft.de/2011/07/17/breaking-dependency-cylces/

But what you describe is not necessary a static cyclic dependency, but one at runtime. I'm not completely sure, but I think it is more or less impossible to avoid cyclic dependencies at runtime. But of course this should not result in endless loops. To fix those I see two and a half options

First the hack

Make sure each event triggered by another event has a reference to the original event (or essential information about it like an id). When ever you process an event make sure it doesn't originate from your self.

Pro: easy to implement; prevents recursion absolutely

The other half of the hack

If you are running synchronous you can set a flag firingEvent before and resetting it after. Ignore events comming in while firingEvent is set.

Pro: even easier to implement; prevents recursion absolutely when running in a single thread

Semantic rich solution

I'm convinced that the event that A fires on some outside trigger and the event that A fires because C fires are really two different events, or all three events are really just one which might come from a yet to be identified source D. Or something like that. There is no way telling without information abut what A, B and C are and what events they are firing. If you find the proper events the cycle will disappear.

Pro: The design will be cleaner and contain more information.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
2

How does one keep such things from happening when designing event based systems?

  1. Raise event only when object state really changes.

  2. Prohibit object state changing while event is raised.

Lightman
  • 1,078
  • 11
  • 22
2

Map out your dependencies. There should be no cycles. Cyclical dependencies are a good excuse to reorganize your code.

They can also cause deadlocks, in case you needed another reason to try to avoid them.

nmichaels
  • 49,466
  • 12
  • 107
  • 135
  • 1
    Yeah but what if your event driven system isn't contained within a single service. For example, if you're running an microservice architecture where each service owns it's own data and you're leveraging event sourcing to keep related data in sync between contexts/services. You don't necessarily know every combination of handlers that could lead to the loop D: – Sinaesthetic Nov 10 '16 at 02:41
0

I think this is a good question. Unfortunately I don't have an full answer myself, but this post has a couple good points:

how to avoid infinite loop in observer pattern?

I don't think the answer is to avoid cyclic dependencies, as others have suggested. (Well, it depends on your definition of "cyclic dependency".) A language like Java will use interfaces to minimize cyclic dependencies of types at compile time, which is often a good idea. For example, a view class in the MVC pattern does not "depend" on your application, it only knows about interfaces with names like ValueChangedListener, ClickListener, etc. But this does not eliminate cyclic connections among objects at run time, which is what can lead to event loops.

As mentioned in the other linked post, some loops are stopped in UI toolkits because the view won't fire a 'changed' event if the controller or model "sets" the view's value to something equal to it's current value. But in other cases, like when you create a custom view of a more complex piece of data, it can be infeasible to compute equality of the current and new data.

Community
  • 1
  • 1
Rob N
  • 15,024
  • 17
  • 92
  • 165
-3

Cyclic dependencies are really bad. I had to write down your post in terms of A, B, and C before it even made sense to me. I think you should get rid of it. If you're putting yourself in a corner, it's probably a whole lot better than the problems you can run into with cyclic dependencies.

You can definitely avoid this, too. A, B, and C are really tightly coupled. I think you need to rethink their responsibilities. Perhaps there's a common D element that'll take a lot of your design-stress away.

Something else that comes to mind is architectural Layering. If you can layer A over B, and require communication by anyone speaking to B to go through A and down the layers, you might give yourself an easier time. Again, I don't know much about your problem, so these are just broad suggestions.

One final option, and my least favorite, is to pass a message between each of the three components. As each is visited, require that each component add to the message that it has seen the message. Then the next component to get the message has information about who's seen it. Kind of like a sign up sheet. But again, least favorite. Try something else first.

Good luck!

Mike
  • 19,267
  • 11
  • 56
  • 72
  • 2
    I don't think he is stating a cyclic dependency but an event cycle. A, B & C are listening for events, lets imagine code is perfectly decopupled through an Observer Pattern. The problems seems to be that he has programmed the code so that changes in one component propagate to another. Nothing to do with code coupling. – Daniel Cerecedo Jun 02 '15 at 13:31