Projections 2: A simple SEP projection

In the first post on projections we talked a bit about the theory behind projections. In this post we are going to try to create a very simple projection and talk about how it actually works.

To start with there is a very special stream inside of the event store. This stream represents statistics measurements that are happening internally. You can control how often they are taken via config. To find this stream in your system you can assuming you are bringing up a brand new node look at the “streams” tab when going to whatever port you set for http.

Hint: as projections are experimental as of the last release you need to enable them on the command line or in configuration when bringing up the Event Store. The command line is –run-projections.

For me (the default) stream for statistics is $stats-127.0.0.1:2113. If you want to see statistics data you can point your browser to 127.0.0.1:2113/streams/$stats-127.0.0.1:2113 and view the data in the stream. You should see something that looks like this:

 

streamviewed

If you click on one of the events you should be able to see the actual data from a statistics event entry. If you want to save some time you can see it on my gist. This is a json encoding of what the statistics measurement looks like. We are going to write a basic projection against that stream.


fromStream('$stats-127.0.0.1:2113').
    when({
        "$stats-collected" : function(s,e) {
              var currentCpu = e.body["sys-cpu"];
              if(currentCpu > 40) {
                   emit("heavycpu", "heavyCpuFound", {"level" : currentCpu})
              }
         }
    });

If you want to test this projection. Go to new projection and paste it in. Give it a name and select “emit enabled” and for mode put “continuous”. We will discuss in a later post what these things mean. The UI around this is currently being changed as well, we see its not the most intuitive.

This is a very simple projection. Its not very interesting. We will get to doing more interesting ones shortly. What it does is it listens to your statistics stream. This is setup when it says “fromStream” this is says “listen to all events in stream s”. It then defines a function that will be passed all $stats-collected events which happen to be the ones we saw in the statistics stream above.

The function declared checks the “sys-cpu” field of the event. If the cpu is higher than 40% it emits a new event out to another stream called “heavycpu”. If you are running the projection you can bring up your CPU usage then try navigating to the stream 127.0.0.1:2113/streams/heavycpu. You will see an event there of the form.

EventStreamId: heavycpu, EventNumber: 2, EventType: heavyCpuFound, Data: {
  "level": 40.9823952
}, Metadata: {
  "streams": {
    "$stats-127.0.0.1:2113": 49
  }
}

This is a very basic projection that is emitting a new event based on some criteria that is found. This is a very common pattern in event based systems (SEP). In the next post we will introduce state into our projection to look at how we can alert not just off a single event but off some group of events that are correlated which is another very common pattern in projections (SEP).

5 Comments

  1. Posted February 13, 2013 at 7:52 pm | Permalink | Reply

    I really like the use of JavaScript for declaring projections, maybe due in part to familiarity with CouchDB and MongoDB. A jQuery-esque syntax would make it even more familiar (at least for those familiar with jQuery) – they both deal with selecting elements and handling events:


    $('$stats-127.0.0.1:2113').on('$stats-collected', function(s,e) {
    var currentCpu = e.body["sys-cpu"];
    if(currentCpu > 40) {
    emit("heavycpu", "heavyCpuFound", {"level" : currentCpu})
    }
    });

    • Posted February 14, 2013 at 1:02 am | Permalink | Reply

      That works quite well for when there is one stream in a projection. As we will see that is not very often the case. Its even rare to join N.

      The places where I love that though is for an indexing projection which needs to see all.

      $($all).on($stats-collected : function(s,e) {linkTo(“stats”, e)});

      • Posted February 14, 2013 at 11:32 pm | Permalink

        In jQuery, multiple elements can be selected with a comma:

        $('$stats-127.0.0.1:2113, another-stream').on(....

        Or am I missing something?

  2. Posted February 15, 2013 at 8:15 am | Permalink | Reply

    for fromStreams(1,2,3,4) it makes sense for $ as well. We will be looking at other selection methods (as mentioned in the theory post fromCategory(account).foreachStream() as example. We did however make a note and will likely add overloads “on” and “$” to the API.

  3. Posted February 15, 2013 at 9:41 am | Permalink | Reply

    the one issue we may have (didnt think about it before) is that in the browser people can use projections/jquery together!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: