Execution Model

Event Loops

An event loop is a message dispatcher. The loop runs, waiting for events, and responding to them. The Kynetx Network Service (KNS) can be envisioned as a system of event loops that run in the cloud. KNS is extremely flexible, allowing developers to create their own event types and then write KRL programs that respond to those events with free form directives.

Event expressions in KRL can be designed to respond to complex event scenarios. KRL includes a set of event operators for combining event primitives into event expressions. Event primitives include some well known and built-in events like those in the Web domain as well as giving developers the ability to define their own event primitives.
See the documentation on event expressions for more information on responding to events from within KRL.

In KNS, endpoints raise events using event API.

Language Execution Duality

The expression of a KRL program takes one of two possible forms, a JavaScript program or a set of directives, depending on the capabilities of the endpoint. Regardless of the ultimate expression of a KRL program, some of the expressions and statements in KRL program are executed by the rules engine and others are executed by the endpoint. Understanding the execution of a KRL program depends on understanding this distinction. The most important distinction to understand is that rule actions are executed by the endpoint and everything else is executed on the rules engine.

When the Kynetx Rules Engine (KRE) produces a Javascript program, care is taken to ensure that any values bound to names on the engine are bound similarly bound to the same names in the expressed Javascript program so that execution of the Javascript on the endpoint has the same environment as existed on KRE. Closures are created to create a similar scoping of names in Javascript as existed on KRE.

Endpoints

KRL is executed by the KNS service calls to the Kynetx Rules Engine (KRE) from an endpoint. There are two main types of endpoints: those that understand Javascript and those that do not. They are described in the following sections.

An endpoint has two primary tasks:

  1. Raise events appropriate to the endpoint type
  2. Respond to the directives sent from KRE in an appropriate manner

For example, a browser extension serving as a Kynetx endpoint would raise the appropriate events for the Web domain including pageview, submit, and so on. The browser extension also responds to directives from KRE. The most important being to execute the returned Javascript in the context of the page.

As another example, an IMAP endpoint would raise events for the Mail domain, including received, sent, etc. and respond to the directives that might include things like delete, forward, and so on.

Each endpoint, regardless of it's domain raises events and executes directives.

Endpoints that Understand Javascript

The quintessential Javascript (JS) endpoint is a browser extension. Kynetx has significant support for delivering Javascript to browsers through various endpoints. Other endpoints that understand Javascript are also possible and work as described below.

The following diagram shows the KNS operations lifecycle and the interplay between a JS endpoint and KRE:

The endpoint exists in three distinct lifecycle phases:

  • Preparation - when it starts or is refreshed, the endpoint makes an API call to the selector to determine the RIDs of any installed cards and then uses that data to call KNS and determine on which domains those RIDs are applicable, called the dispatch list.
  • Wait - the endpoint exists in a wait state until it detects a page with a domain that matches a domain on the dispatch list. When that happens it initiates KRE execution as described below. When the execution is completed, the endpoint returns to a wait state.
  • Finalize - when the browser is closed, the endpoint completes any clean up tasks and ends.

There are three stages in KRL execution by KRE:

  • Initialization
  • Evaluation
  • Callback

These are described in detail below

Initialization

Initialization configures and initiates the endpoint by downloading a runtime appropriate to the endpoint type.

Configuration is performed by adding a script tag to the page that defines the KOBJ_config object like so:

<script type="text/javascript">
var KOBJ_config ={
   "rids"  : ["kntx_rulealert","kntx_rulealert_2"],
   "init"  : {"eval_host" : "cs.kobj.net","callback_host":"log.kobj.net"},
   "key_1" : "value_1",
   "key_2" : "value_2"
};
</script>

The config object must contain an array names "rids" that contains the RIDs of rulesets applicable to this page. The config object can also contain an optional object named "init" that can override the URLs of the eval and callback host. The "init" object will not be included under most circumstances.

The other components of the config object are parameters that will be passed to the ruleset when it is evaluates. These can be read and tested using the page:param function in KRL (without the namespace designation). Parameter names should be namespaced by prepending RID with a colon (:) separator like so:

var KOBJ_config ={
   "rids"  : ["ruleset_1","ruleset_2"],
   "ruleset_1:ex_param" : "3",
   "ruleset_2:ex_param" : "5",
};

Parameters must be namespaced by the ruleset ID to be visible in KRL.

After the config object as been added to the page, the evaluation is initiated by adding this tag to the page:

<script type="text/javascript" src="http://init.kobj.net/js/shared/kobj-static.js"/>

This loads the KRL runtime library and initiates execution.

Evaluation

The initialization process will add tags to the page that cause ruleset evaluation to commence. The process results in a custom Javascript program being returned to the endpoint. In the case of a browser endpoint, the Javascript program will run in the context of the current page.

Callback

Some rules create explicit callbacks to KNS for various activities that the user takes. These are managed by the endpoint.

Directive Endpoints

Any device or program that is connected to the Internet and understands HTTP can serve as an endpoint. As described above, endpoints have two primary tasks:

  1. Raise events appropriate to the endpoint type
  2. Respond to the directives sent from KRE in an appropriate manner

Raising an event is accomplished using the event API. By forming the appropriate URL and then using HTTP to call it, the endpoint raises the event.

The result, for endpoints that do not understand Javascript, will be a directive document. A directive document is delivered as JSON that takes the following form:

{"directives":
  [{"options":{<name>:<value>[,<name>:<value>]*},
    "name":<directive_name>,
    "meta":{
      "rule_name":<rule_name>,
      "txn_id":<txn_id>,
      "rid":<rid>
      }
   }
  ]
}

For each object in the directives array, the endpoint uses the directive name and options to take a particular action. The meta information contains the name of the rule that returned the directive, the ruleset ID that the rule belongs to, and a transaction ID. The transaction ID is guaranteed to be globally unique and will be the same for every directive in a given directive document.

Event and Endpoint Example

The following example shows a simple endpoint written in Perl that implements an echo server and client.

#!/usr/bin/perl -w
use strict;

use Getopt::Std;
use LWP::Simple;
use JSON::XS;

use Kynetx::Raise;

# global options
use vars qw/ %opt /;
my $opt_string = 'h?e:m:';
getopts( "$opt_string", \%opt ); # or &usage();

my $event_type = $opt{'e'} || 'hello';
my $message = $opt{'m'} || '';

my $event = Kynetx::Raise->new('echo',
			       $event_type,
			       'a16x66',
			       {'host' => '127.0.0.1'}
			       );

my $response = $event->raise({'input' => $message});

foreach my $d (@{$response->{'directives'}}) {
  if ($d->{'name'} eq 'say') {
    print $d->{'options'}->{'something'}, "\n";
  }
}

This simple script uses a module called Kynetx::Raise that takes the relevant information about the event, creates the right URL for the Kynetx event API, raises the event by calling the URL, and processes the response. You can see that it has the possibility of taking the event type from the command line with the -e switch. If none is given, the event type defaults to hello.

To function, this endpoint needs a corresponding set of rules to react to the events it raises. Here are two such rules:

rule hello_world is active {
  select when echo hello
  send_directive("say") with
    something = "Hello World";
}

rule echo is active {
  select when echo message input "(.*)" setting(m)
  send_directive("say") with
    something = m;
}

The rule hello_world responds to the hello event by sending the directive named say with the parameter something set to "Hello World". The rule echo responds to an echo event with a parameter called input. That entire value of the input is caputured and bound to the variable m. The echo rule send a directive named say with the parameter something set to the value of m.

It's critical to note that the underlying KNS engine doesn't know anything about the event domain echo or the event types hello and message. We could define these to be anything we wanted and the example would work the same.

If the endpoint is run with no arguments the default event type, hello, is raised which results in the hello_world rule we defined above firing and the directive say "Hello World" being sent to the program which prints the message.

Running the program with the -e switch like so:

./echo.pl -e message -m 'KRL programs the Internet!'

raises the event type message in the echo domain. KNS returns the following directive document:

{"directives":
  [{"options":{"something":"Hello World"},
    "name":"say",
    "meta":{
      "rule_name":"hello_world",
      "txn_id":"8FF45D92-7EDB-11DF-B34A-4BA9F4723EB4",
      "rid":"a16x66"
      }
   }
  ]
}

The perl program shown above consumes this directive document which
results in the string KRL programs the Internet! being printed in the terminal.