Raising Events Asynchronously


Summary

Adding the ability to process events asynchronously has huge benefits for performance in an event processing system. With a small change to the code, we've enabled asynchronous events and made the event engine more performant in important situations.

Astronomical Clock

I've often described Sky, the Kynetx event protocol, as an "event-response" protocol, a cross between a synchronous request-response protocol and an asynchronous event protocol. Sky has always processed events synchronously, even when no response was necessary. There are many times that the event generator does not need a response from the processor and would just as soon get on with its business. I imagined all kinds of complicated ways to make Sky asynchronous.

Mark Horstmeier had an ingenious idea: just use the mod_perl cleanup handler. Since we're using Apache as our application server this made things relatively easy. The cleanup handler runs as the very last thing in the HTTP request cycle. Consequently, the response has already been sent back by the time it runs as this document from the mod_perl project shows:

Apache HTTP Request Cycle

Mark simply moved the synchronous handler to the name _handler and then registers it with the clean-up handler if the _async parameter is true, or calls _handler directly if it's not:

sub handler {
  my $r = shift;	
	
  my $req = Apache2::Request->new($r);
  if ($req->param('_async'))	{
    //------ Asynchronous evaluation---------
    $r->pool->cleanup_register(\&_handler,$r);
    return Apache2::Const::OK;
  } else {
    //------ Synchronous evaluation----------
    _handler($r);
    return Apache2::Const::OK;
  }
}

A few lines of carefully crafted Perl and we have asynchronous events. Beautiful!

The first use of this is to make the event:send() action asynchronous by default. This action is most often used in situations where events are being sent to a number of other personal event networks. While event:send() is engineered to send those events in parallel, you still have to wait for them to return and the overall execution time is at least as long as the longest. With asynchronous execution, this is no longer the case.