Summary
Events are processed in KRE using an event loop that decodes the event, makes a schedule, evaluates the respond, and finally assembles a response. This post describes the details of the event evaluation cycle in KRE and how explicit events affect rule schedules.
In my post on the event-query API that picos present to the world, I talked about picos listening for events and responding, but there wasn't a lot of detail in how that worked. This post will describe the event evaluation cycle in some detail. Understanding these details can help developers have a better feel for how the rulesets in a pico will be evaluated for a given event.
Each pico presents an event loop that handles events sent to the pico according to the rulesets that are installed in it. The following diagram shows the five phases of event evaluation. Note that evaluation is a cycle like any interpreter. The event represents the input to the interpreter that causes the cycle to happen. Once that event has been evaluated, the pico waits for another event.
We'll discuss the five stages in order.
Wait
The wait phase is where picos spend more of their time. For efficiency sake, the pico is suspended during the wait phase. When an event is received KRE (Kinetic Rules Engine) wakes the pico up and begins executing the cycle. Unsuspending a pico is a very lightweight operation.
Decode Event
The decode phase performs a simple task of unpacking the event from whatever method was used to transport it and putting it in a standard RequestInfo
object. The RequestInfo
object is used for the remainder of the event evaluation cycle whenever information about the event is needed.
While most events, at present, are transported over HTTP via the Sky Event API, that needn't be the case. Events can be transported via any means for which a decoder exists. In addition to Sky Event, there is also support for an SMTP transport called Sky Mail. Other transports (e.g. XMPP, RabbitMQ, etc.) could be supported with minimal effort.
Schedule Rules
The rule scheduling phase is very important to the overall operation of the pico since building the schedule determines what will happen for the remainder of the event evaluation cycle.
Rules are scheduled using a salience graph that shows, for any given event domain and event type, which rules are salient. The event in the RequestInfo
object will have a single event domain and event type. The domain and type are used to look up the list of rules that are listening for that event domain and type combination. Those rules are added to the schedule.
The salience graph is calculated from the rulesets installed in the pico. Whenever the collection of rulesets for a pico changes, the salience graph is recalculated. There is a single salience graph for each pico. The salience graph determines for which events a rule is listening by using the rule's event expression.
Rule order matters within a ruleset. KRE ensures that rules appear in the schedule in the order they appear in the ruleset. No such ordering exists for rulesets, however, so there is no guarantee that rules from one ruleset will be evaluated before or after those of another unless the programmer takes explicit steps to ensure that they are (see the discussion of explicit events below).
The salience graph creates an event bus for the pico, ensuring that as rulesets are installed their rules are automatically subscribed to the events for which they listen.
Rule Evaluation
The rule evaluation phase is where the good stuff happens, at least from the developer's standpoint. The engine runs down the schedule, picking off rules one by one, evaluating the event expression to see if that rule is fired and then, if it is, executing the rule. Note that a rule can be one the schedule because it's listening for an event, but still not be selected because it's event expression doesn't reach a final state. There might be other event that have to be raised before it is complete.
Four purposes of understanding the event evaluation cycle, most of what happens in rule execution is irrelevant. The exception is the raise
statement in the rule's postlude. The raise
statement allows developers to raise an event as one of the results of the rule evaluation. Raising explicit events is a powerful tool.
From the standpoint of the event evaluation cycle, however, explicit events are a complicating factor because they modify the schedule. Explicit events are not like function calls or actions because they do not represent a change in the flow of control. Instead, an explicit event causes the engine to modify the schedule, possibly appending new rules. Once that has happened rule execution takes up where it left off in the schedule. The schedule is always evaluated in order and new rules are always simply appended. This means that all the rules that were scheduled because of the original event will be evaluated before any rules schedule because of explicit events. Programmers can also use event expressions to order rule evaluation.
If the rule makes a synchronous call to an external API, rule execution waits for the external resource to respond. If a rule sends an event to another pico, that sets off another independent event evaluation cycle, it doesn't modify the schedule for the cycle execution the event:send()
. Inter-pico events are sent asynchronously by default.
Assembling the Response
The final response is assembled from the output of all the rules that fired. The idea of an event having a response is unusual. For KRE it's a historic happenstance that has proven useful. Events raised asynchronously never have responses. For events raised synchronously, the response is most useful as a way to ensure the event was received and processed. But the response can have real utility as well.
Historically, KRE returned JavaScript as the result of executing rules. That has been expanded so that the result can be JSON or other correctly mime-typed content. This presents challenges for the engine since rules could be written by many different developers and yet there can be only one result type.
Presently the engine handles this by assuming that any response to an event with the domain web
will be JavaScript and otherwise be a directive document (JSON with a specific schema). This suits for many purposes, but doesn't admit raw responses such as images or even just a JSON doc that isn't a directive. The engine tries to put a correctly formatted response together as best it can, but more work is needed, especially in handling raw responses.
This isn't usually a problem because the semantics of a particular event usually imply a specific kind of response (much as we've determined up front that JavaScript is the correct response for events with a web
domain). Over time, I expect more and more events will be raised asynchronously and the response document will become less important.
Waiting...Again
Once the response has been returned, the pico waits for another event.
Conclusion
For simple rulesets, a programmer can largely ignore what's happening under the covers and the preceding discussion is overkill. But applications that consist of multiple rulesets, complex pico structures, or many explicit events can have asynchronous interactions that the developer must understand to avoid pitfalls like race conditions.
If you'd like to add other transports to KRE, we welcome the help. KRE is an open source project hosted on Github. We're happy to help you get started.
The event evaluation cycle described above presents programmers with a flexible, programmable, cloud-based way to respond to events. Explicit events add significant power by allowing the rule schedule to be expanded on the fly. The salience graph provides a level of indirection, binding events to rules in a way that is loosely coupled and dynamic. The event loop is the source of much of KRL's power.
Related: I originally introduced the idea of KRE creating an event loop in A Big, Programmable Event Loop in the Cloud. At that time, 2010, the concept of picos and salience graphs was not fully developed. Those were made possible by the introduction of the Sky Event API in 2011.