FREE Subscription to Dr. Dobb’s Digest: Same Great Content, New Digital Edition
Site Archive (Complete)
Architecture Blog: Events and Temporal Coupling
Architecture & Design
PATTERN LANGUAGE

Modeling, Managing, Making it Right.

by Jonathan Erickson
IF YOU BUILD IT

... Will they Come?

by Arnon Rotem-Gal-Oz
June 28, 2007

Events and Temporal Coupling

You raise an event when something interesting happens. You think it is important, but you don't care enough to know who is interested. You are even less interested in personally going to each and every interested party and letting them know. So instead, you raise an event -- and let the poor buggers take care of any implications by themselves. We raise the event "now" when the change happened. It is only important now anyway....

Looking from the "poor buggers" point of view (the event consumer), things are more complicated. There are events which are cyclic in nature (like stock price updates, the blips from a sonar etc.) where if you miss a blip, then it isn't really important. You'll get the right information in the next update (actually, that's not always true; keep reading). Then there are the events which only occur once. Sometimes it isn't important for you to listen to them if you are not up and running in the same time. Other times you can't afford to lose an event; for instance, if your ordering service (or component for that matter) communicates with the invoicing service using events, missing the event of a new order means you lose money.

This basically means that the event producer and the event consumer are coupled in time. Which means that you need to make sure both of these services are available at the same time -- if the invoices crashed, then processing orders should be suspended. This doesn't mean that you don't accept orders, just that you don't process them.

Okay, maybe we can just raise the event "transactionally". This would probably work, but you need to remember that the event producer doesn't really care about the event consumers. Why would it want to fail because of them?!

Maybe a better way would be to "raise" the event over some reliable transport. But this has a few problems. For one thing, we've passed the problem to the connection between the event producer and the transport. It might be acceptable to have a transaction between the event producer and the transport. But as I've already said, the producer doesn't care much about the consumers.

We can have persistent subscriptions for existing consumers to prevent events from getting lost which make both create a minor problem that new consumers can't see past events. Also it has the risk of existing subscribers disappearing and their queue can then grow endlessly (or until an administrator removes the subscription).

Okay, let's look at the problem from a different perspective. Looking at the events, what we can really see is that an event has a time-to-live (TTL) as far as the event consumer is concerned. For instance, in the case of the cyclic events, the TTL is the interval until the next event. Actually, even with cyclic events the TTL might be larger. If we are also interested in analyzing trends or abnormal occurrences (which is why I said it isn't entirely true we don't care about old events). In case of one-time events, the TTL might be indefinite or maybe even then it might be some definite value (one day, week, year etc.). Since we can't know about the TTL of consumers it can be a good idea to make past events available somehow.

Thus, when you design an event-centric architecture like EDA (whether on top of SOA or not), it is important to think about event consumers -- we don't want to think about specific consumers since it negates the benefits of thinking in events. However I would say that you want to think about event consumers in general, after all your component is also an event consumer ("do unto others as you would have them do unto you").

One option which I already talked about is to make past events available as a feed. Event consumers can then come at their own leisure and consume past event (this can be in addition to raising the events in real-time). This provides a partial solution as the maximal TTL is determined by the event producer (after which the event is deleted from the feed). This may be acceptable but you must be aware of that.

The other option is to to log all the events and provide an API to retrieve past events. In a sense the max TTL is still at the hands of the event producer only if you use a database it would probably be a large time compared with a feed. Alternatively the events can be logged on by a central "always present" event aggregator (in a manner similar to the aggregated reporting pattern I described for SOA).

To sum up: Events they seem only to matter in the instance in time they are created, we are used to that thinking from building object-oriented systems where all the components are co-located in the same address-space and time (even there I can think of scenarios where we would want past events). In a distributed world events need to have a TTL. The TTLs can vary and are determined by the events consumers. Lastly, as I demonstrated in the previous paragraph, there are several strategies we can use to help solve the event TTL dilemma (and there are probably a few others).

Posted by Arnon Rotem-Gal-Oz at 10:24 AM  Permalink




 
INFO-LINK