In
this my third installment on a series devoted to the
Apama
Event Processing Language (EPL), I'll continue where I left off last
time in which I described the basic design of event passing for a consumer/producer
model. For this revision I've extended the model to support
multiple consumers. This introduces the instance
management
feature of the Apama EPL. Instances or 'sub-monitors' as
they're often referred to define a discrete unit of work. The unit
of work can be very small (an analytic calculation) or very large (a
whole trading algo). Each instance gets spawned with it's own
parameter set, listens for it's own event streams and operates in a
very singleton manner. To which I mean, within the
semantics of the application an instance need only be concerned about
managing itself not other instances. Overall, it
is a factory
behavioral model extended to include an execution
model.
This is a key aspect of the Apama EPL, making
a common
application requirement simple to implement, robust in design,
and highly performant in the CEP model.
The Apama CEP engine manages the execution of these sub-monitors (also known as mThreads internally). In a typical production deployment, there would be 100's or 1000's of sub-monitors running. The spawn operator is the single statement in the language that accomplishes this unique feature. Spawn is basically a self-replicating scheme with certain behavioral rules. The main rule: the cloned instance does not get the active listeners (i.e. on all someEvent...) of the parent. It must establish it's own. Actually it's the perfect model for that factory-like behavior. The clone does not want it's parents listeners, but would create it's own based on the parameters passed such as the symbol name in a trading algo or the subscriberId in our Producer example below. Speaking of our example ...
For the sake of brevity, I've just listed the extended Producer side of my consumer/producer example below. For the complete example, you can download it here.
package
com.apamax.sample;
monitor ItemService { action startSubscriptions(integer
this_subscriberId, string name) {
on UnsubscribeFromItems(subscriberId = this_subscriberId):u {
|
To get a general sense of what this bit of code is intended to do, I suggest a quick scan of my previous installment where I introduced this example.
The extended Item Producer is expected to manage multiple uniquely identified consumers. For that it must maintain a list of identifiers, one for each consumer. It does that by appending and removing entries from an array (sequence<integer> ids). his is a common idiom for tracking identifiers, syntactically it's similar in many imperative languages.
This example uses a single-cast event passing scheme where the Producer routes Item events uniquely tagged to the consumer (route Item(this_subscriberId, name, count, price)).
On the consumer side, Item events are listened for based on a subscriberId (on all Item(subscriberId = myId)). It's the uniqueness of subscriberId (one per consumer) that defines this as a single-cast design. A common twist to this a multi-cast event passed scheme (not be be confused with the UDP multicast) where multiple consumers might be requesting the same information (i.e. the item_name in our example). A well understood example of this would be a market data adapter providing trade data for the same symbol to multiple consumers. The Item Producer would change very little to support a multi-cast event passing scheme.
In the listener "on all SubscribeToItems()", we spawn to the action startSubscriptions when we receive a SubscribeToItems event from a consumer. We pass the parameters of the consumer's identifier (s.subscriberId) and the item (s.item_name) to instantiate the new sub-monitor. A new mThread of execution is created for the sub-monitor and it begins executing producing Item events. The parent monitor continues waiting (listening) for another SubscribeToItems event.
You'll also notice the use of a private event ClearUserID, the purpose behind this is to communicate between the spawned sub-monitor(s) and main (parent) Monitor when an UnsubscribeFromItems request is received. This is necessary since the parent monitor manages the id's of connected consumers. A spawned sub-monitor uses this event to simply inform of termination.
The event paradigm in the Apama EPL extends far beyond the notion of processing data events. In one sense you could categorized events as data and control. Data events are consumed and processed by the CEP application. Control events direct the semantics of the application.
This example is designed to illustrate a few powerful yet easy to use features of the Apama EPL:
Here's the complete example with the consumers, interface and producer.
Once again thanks for reading,
Louie
View all posts from The Progress Team on the Progress blog. Connect with us about all things application development and deployment, data integration and digital business.
Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.
Learn MoreSubscribe to get all the news, info and tutorials you need to build better business apps and sites