Consider reactive functionality available in Prova (see Reactive messaging). If we wanted to "string" together a number of reactions in order to detect an event pattern, the simplest idea would be to use one reaction per event type that is part of the pattern. In fact, we could actually implement a "followed by" operator pretty easily, by literally following up one reaction with another as in the example below.
This is brilliant, we could even set constraints on the received messages using guards.
There are many gaps in this first attempt. Let us consider how we could introduce a timeout.
Note the use of the @timeout annotation above. This is an improvement as we are now able to wait for the follow-up event for a limited amount of time.
This is still imperfect, what if the first message fails to materialise at all? What we need is a collective reaction, a notion of a group context associated with a number of individual reactions. We want to associate a timeout with that group as a whole while still being able to specify timeouts on individual reactions. Enter the @group annotation.
The idea here is to group the reactions in one AND group and say "we want both of these events to arrive". The group members, that we call event channels are decorated with the @group annotation that can carry a list of logical group names. You may ask about the scope of this logical group name "g1" in this example. The group "g1" is just a template, the actual group instance is created each time the login event is detected in the very first clause for predicate server. All of those concrete group instances then co-exist and concurrently detect the follow-up sequences of a logout followed by a login from another IP.
We limit the detections to a "followed by" pattern by allowing the second reaction to only occur after the first, in the first clause for the group.
The all-important second clause for the group reaction includes a group reaction annotated with the type of the group, which is @and in this instance. This is exactly where we attach additional constraints on the pattern reaction as a whole, so we place the second group-wide @timeout there.
What exactly is this group reaction? When the Prova engine finds a group, it builds all the group members and observes the semantics of the group. If it is an AND group, when all the conjuncted reactions are successfully detected (within the overall specified timeout), the special event of message type and is sent internally and its payload, captured in the variable Events, contains the full history of events that resulted in the pattern detection.
To recap, event processing in Prova is based on reactive messaging augmented with the ability to group reactions together so that they "collaborate" for the event patterns detection.
White box or workflow event processing
It is critical to observe that each reaction in the pattern still retains its context. This style of reacting is different from typical stream processing engines because it leaves the workflow associated with the detection process open for arbitrary logical or procedural extensions whenever each individual event in the pattern is detected. For example, we can log or send messages right from within the pattern. This becomes particularly important when we want to achieve a measure of completeness associated with a pattern detection.
Consider a refinement process whereby a pattern becomes increasingly more complicated as we strive for detection precision. The adverse effect of this is the loss of generality, the pattern may become overly specialised and brittle. The workflow languages recognise the need for fault or compensation handlers and that is precisely what is lacking in stream processing. The collective Prova reaction style leaves the box open for workflow inspection and manipulation so that a pattern becomes much more accommodating to variation.
The second distinguishing feature of the event processing in Prova is that timeouts or partial detections result in the full trace of partial results being emitted in a special message with type timeout.
The example above contains an entirely optional second clause that reacts to this internal timeout event and, in this instance, simply prints these partial results. This could be used for diagnosing why the pattern was not fully detected and organising possible counter-measures.
These design decisions help to increase the robustness of event processing in Prova.