2

I find it difficult to explain but I'll give it a try. I have a module structure where the modules can fire events and other modules respond to them.

enter image description here

As you can see, B & C are listening to events from A, D listens to events from B & C (but doesn't need the event from A)

Now the problem is: since the modules are created dynamically, I can't force the registration order for the events (they can be asynchronous). So D is not 100% guaranteed to receive B's event before C's event. In fact, C might not send an event. (this could possibly be enforced)

D has to react and most likely does recalculations and it would be a shame that he has to do this twice or even more. I had come up with something myself with a kind of timeout (if no event within x time, I can recalculate that, but I get the feeling that this is mainly sticking tape.)

Is there anyone who happens to have a methodology or other way of thinking to ensure that things are not calculated unnecessarily often.


(reaction to pjc50)

No, the events aren't the same type. In realworld example it's about robotic machine software (pickerline), which is build with modules. An example would be, a A is a recipe module which fires a recipechanged event, B is a robotic workarea module which fires an event that the area is changed (for example other product types). C could be a Transport control module which fires a change of speed. It all affects the D robotic module to pick products. The explanation does not quite correspond to the real implementation, but the point is that B and C have nothing to do with each other, but D does depend on what B and C indicate. Somehow I would like to be able to put that together.

Only A knows when the underlying modules are ready. But to now have to make a reference from D to A, is not quite right in my view. Even when I register from the D to A's RecipeChanged, it's still the question about the order of raising the events to the listeners. Then I would have to make an event RecipeChangedFinished (but what if module D isn't the last one and some other module is dependend on D)

I think it all leads to not knowing the order of events fired, is my problem

So I would like to know if there are other pattern which I'm not aware of. (or I might be thinking wrong)

(I'd like to learn to be doing better)

4
  • A option would be to use a key or something and simple discard duplicates
    – Darem
    Commented Jan 12, 2022 at 10:12
  • @Darem Also thought about that, passing a token or something as argument or using a ThreadLocal. But the problem remains, "Was it the last event, or need other modules to be updated. so it needs to be recalculated." Commented Jan 12, 2022 at 10:18
  • So .. what actually are the events? Do both B and C send the same type of event? Do they both theoretically require some kind of response? Is it possible for them to fire for other reasons? Could you simply take one of the BD or CD links out?
    – pjc50
    Commented Jan 12, 2022 at 10:29
  • @pjc50 I've added some extra information to the question (it was too long to post as comment) Commented Jan 12, 2022 at 10:42

1 Answer 1

4

Based on the extra information, this sounds quite similar to a problem in GUI design: avoiding unnecessary refreshes. An example might be having an event that changes the content of a textbox and another that changes the color of the textbox. Here's a discussion of the problem in React, for example.

It's quite difficult to avoid in general. Possible approaches:

  • React (and other systems) check to see if values have actually changed when they receive a "value changed" event, and if the value is the same as the last input to the calculation they do not rerun the calculation or send the event downstream.

  • If there's different events with the same underlying cause, and ordering is guaranteed within a message stream, a BeginChange/EndChange approach can work. Suspend expensive updates until you get an EndChange.

  • Limit the output side to one update per "frame", on a timer. This (and any other timer-based approach) increases latency.

  • (based on digital logic propagation) Group the modules into "waves" and execute their responses to events in order. A is wave 0, B and C are wave 1, D is wave 2. This can be done with a topological sort on the graph.

  • Restructure to "pull" from "push": while event source architectures are popular, the older approach of simply starting from the end and recursively asking "do you have any updates for me?" can also still work. In that case you'd have D poll B which polls A, then C polls A, and only then would D update itself.

Fundamentally there's a CPU usage / latency tradeoff here. You can make it more efficient by doing fewer updates, but if you delay processing D until everything is ready then in some circumstances you will have waited longer than just responding to the first update.

1
  • I can get some valuable information out of this, thanks for taking the time to share it. I think the BeginUpdate/EndUpdate in combination with Wave, might lead to a better solution. For example: Splitting the event in two events, handling the events on the first and do the recalculation on the second from there start a new 'wave' with a begin/end, i'll think about that. Thank you. Commented Jan 12, 2022 at 12:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.