Wednesday, February 15, 2012

An Implementation

Get caught up:
Part 1: http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html
Part 2: http://randomgoo.blogspot.com/2012/02/events.html
Part 3: http://randomgoo.blogspot.com/2012/02/event-listeners-get-up-to-speed-first.html
Part 4: http://randomgoo.blogspot.com/2012/02/event-hub.html
Part 5: http://randomgoo.blogspot.com/2012/02/deploying-event-hub-application.html

Quick recap - Web 3.0 is two-way asynchronous programming - events on the way out and another event or a callback on the way back.

I have cobbled together an Event Hub implementation here: https://github.com/zzo/EventHub.
This implementation happens to be in Javascript and it built upon socket.io.  Which means besides being very easy to add to client-side modules, there is support for many languages on the server side including Erlang, Lua, Java, Perl, Go, Python, Ruby, Flash, and of course Javascript.  See the socket.io wiki for details.  The Event Hub itself is also available as an npm package.

The actual Event Hub code is very small.  It actually uses the connect frame work for transport and serves the static socket.io and Event Hub client libraries itself (there are currently 2, one for YUI and another for jQuery - feel free to add more!).  There is also a NodeJS client-library for NodeJS client to connect to the hub.  Check out the examples/ directory for how to use all of this stuff.

You have a couple choices when starting server-side event hub modules.  They can either all be completely separate processes, which is cleanest.  Each server-side module would sit on its own port connected to the event hub completely independent of each other.  They can all be on separate hosts, however you want to do it - they are all completely separate from each other.
You can also start them all up in one shot and multiplex their port amongst them.  While this is perhaps easier to do initially, if you need to restart any one of them you will need to restart all of them.

Let's look at some examples!

Here is a NodeJS EventHub client:

var eventHub = require('eventClient.js')
                     .getClientHub('http://localhost:5883?token=SECRET');

eventHub.on('eventHubReady', 
    function() {
        eventHub.on('HelloWorld', 
            function(data, callback) {
                // SESSION key is in data['eventHub:session']
                callback(null, { mark: 'trostler' });
             }
            , { type: 'unicast' }
        );

        eventHub.on('eventClient:done', 
            function(event) {
                console.log('DONE LISTENING FOR ' + event);
                // wait for us to finish processing any current
                //    event and then....
                process.exit(0);
            }
        );
    }
);

So we connect to the hub using the secret key ('SECRET' in this case). If we successfully connect (because the token is correct) we become a 'trusted' module and can listen for 'unicast' events.
If the connection is established we listen for a 'HelloWorld' event, telling the EventHub this is a 'unicast' event - so only send these events to us. That also means the Hub will sent us an 'eventClient:done' event if someone else comes along and starts listening for this event too - so we also listen for that event. If we get that event we shut ourselves down gracefully. And finally 'trusted' modules will also receive the session key of the client who emitted this event - and will be available to this modules in data['eventHub:session'] in the event data.
Upon receiving a 'HelloWorld' event, we do some processing and call back to the emitted using the supplied callback. We follow the convention that the first argument of the callback is an error object or string if there was an error, and whatever data in the second callback argument.

Now let's look at something that might emit this event:

<html>
<head>
</head>
<body>
 <script src="http://yui.yahooapis.com/3.4.1/build/yui/yui-min.js"></script>
 <script src="http://dashr.net:5883/socket.io/socket.io.js"></script>
 <script src="http://dashr.net:5883/yui3.js"></script>
 <button id="button">Press Me</button>
<script>
    YUI().use('node', 'EventHub', function(Y) {

        var hub = new Y.EventHub(io, 'http://dashr.net:5883');
        hub.on('eventHubReady', function() {
            var helloWorld = hub.addEvent('HelloWorld');
            Y.one('#button').on('click',
                function(event) {
                    helloWorld.fire({ button: 'clicked' },
                        function(error, data) { 
                            Y.log("callback from event listener!");
                        }
                    );
                }
            );
            hub.on('someOtherEvent', function(data, callback) {
                Y.log("Got some other event!");
                callback(null, { hello: "stranger" });
            });
        });
    });
</script>
</body>
</html>

Ok so check it out - first we load the YUI seed (we'll use the YUI EventHub client), socket.io and the YUI event hub library. Note we can load those last two scripts directly from the EventHub itself.
We then connect to the hub and when ready we use a convenience function in the client YUI library to create a 'shortcut' for the HelloWorld event we are going to fire.
So when someone clicks our button we fire the HelloWorld event and set up the callback for the response. At some point the callback comes back and Bob is your uncle.

Listening for events is just as easy, here I'm not using the convenience 'addEvent' method and just listening for 'someOtherEvent' and calling its callback function back when I get it.

The jQuery example is remarkably similar!

<html>
<head>
</head>
<body>
 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.js"></script>
 <script src="http://dashr.net:5883/socket.io/socket.io.js"></script>
 <script src="http://dashr.net:5883/jquery.js"></script>
 <button id="button">Press Me</button>
<script>
    var hub = new $.fn.eventHub(io, 'http://dashr.net:5883');
    hub.bind('eventHubReady', function() {
        var helloWorldEvent = hub.addEvent('HelloWorld');
        $('#button').bind('click',
            function(event) {
                console.log('clicked on button - making new event for hub');
                console.log(clickEvent);
                helloWorldEvent.trigger({ button: 'clicked' },
                    function(error, data) { 
                        console.log("callback from event listener!");
                    }
                );
            }
        );
     
        // listen for some other event
        hub.bind('someOtherEvent',
            function(data, callback) {
                console.log('got someOtherEvent');
                console.log(data);
                callback(null, { mark: 'rox' });
            }
        );
    }); 
</script>
</body>
</html>

For jQuery we use the jQuery syntax of 'trigger' and 'bind' instead of 'fire' and 'on' but everything else is pretty much the same. We use the client utility method 'addEvent' for the HelloWorld event but don't for the 'someOtherEvent', totally optional to use the syntactic sugar 'addEvent' provides for you.

It's equally easy to add clients in other languages that socket.io supports - or any language with a Web Sockets library.

Finally starting the event hub is easy:

% node eventHub.js

For now you need to edit 'eventHub.js' itself if you want to change the port (5883) or the secret used to determine trusted clients.

If you installed EventHub using npm try:

% npm start EventHub

Have fun out there and stay tuned for even more!!

Deploying an Event Hub application

Get caught up:
Part 1: http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html
Part 2: http://randomgoo.blogspot.com/2012/02/events.html
Part 3: http://randomgoo.blogspot.com/2012/02/event-listeners-get-up-to-speed-first.html
Part 4: http://randomgoo.blogspot.com/2012/02/event-hub.html

Quick recap - Web 3.0 is two-way asynchronous programming - events on the way out and another event or a callback on the way back.


An oft overlooked key piece to any application is its deployment.  Deploying a 'traditional' HTTP-server based application is a one-shot all-or-nothing affair.  Typically even the smallest server-side change requires a full-blown deploy and restart of all of your HTTP servers.  Well that blows.


Compare with an event-based application consisting of a federation of independent processes that comprise the application.  You only need to deploy and restart small, independent pieces of the application for updates, not the entire thing.


Now it's not all wine and roses (or beer and dandelions).  There is more complexity because there are more pieces.  But small and independent beats large and monolithic even with the extra complexity, of which there isn't that much.


But the biggest issue is dropping events.  HTTP servers have 'graceful' shutdowns, ensuring all current requests are satisfied before shutting down, ensuring remote clients aren't left in the lurch during a restart, what about Event Hubs?


Glad you asked, let's look at the scenarios:


Server Side


1. Broadcast events


Broadcasted events are sent to every connected module.  Each broadcast event listener should listen for a signal or other outside data that tells it to shutdown.  So to shut down and restart a broadcast event listener, simply bring up the newer version of the listener and tell the old one(s) to shutdown.
Like a 'graceful' shutdown the current about-to-be-shutdown listeners should immediately stop listening for the given event, wait until they are done servicing any existing events, and then shut down if that is the only event that module is listening for.


Here is where putting a version number in the event name is also useful.  If using this method bring up the new listener that listens for the new event name with the updated version number and update the clients to use this new event name.  As clients start calling the new event name (with an updated version number in it) the old listeners duties trickle away until it can be safely killed.


2. Unicast Events


This is even easier as the event hub notifies the old listener (via an event) when a new one takes over that it has been replaced and can stop listening for the unicast event.  At that point the listener will finish with any current events its dealing with and then shut down.


So you need only the bring up the newer version of the unicast listener, it will connect to the hub, telling the hub it is the new listener for the given unicast event.  All subsequent unicast events will get passed to the new listener and the old listener will receive a event from the hub telling the old listener that its work is done.


Client-Side


The above two scenarios detail how to shutdown old server-side listeners, what about updating clients?  Welp that is no different than what we currently do when we roll out new client-side web application code: push the code out the the CDN.  Your HTTP server is still around to server the static client-side code.  Subsequent browser refreshes will now get served this new code.  Same deal.
What is more interesting is the client-side code is split into many smaller individual files which can be changed independent of all the other files.  It's not quite as clean as that because for efficiency the small Javascript files would be mashed into one large one and then minified for performance, regardless the process is the same as for current web applications.
Deploying small changes in client-side code is a very interesting topic and I hope someday to learn how to do it better...


The Hub


What about the hub itself?  The time will come when it needs to be restarted for whatever reason.  The best way is to bring up a new hub and bring up another set of listeners that connect to it.  Update client-side code to point to the new hub and push it out.  Wait.  Wait some more.  Eventually traffic to your old hub will cease, then you can shut it down and shut down all the listeners connected to it.
When is safe to shut down the old hub?  Where there is no more client traffic!  We'll look at that in the 'Logging' post coming up soon!


I hope you can see deployment of event-based asynchronous application is more complex because there are more pieces but much more fine-grained and much safer overall.


Stay tuned for Logging, languages, and an implementation!

Tuesday, February 14, 2012

Event Hub

Event Hub


Get caught up:
Part 1: http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html
Part 2: http://randomgoo.blogspot.com/2012/02/events.html
Part 3: http://randomgoo.blogspot.com/2012/02/event-listeners-get-up-to-speed-first.html

Quick recap - Web 3.0 is two-way asynchronous programming - events on the way out and another event or a callback on the way back.


The hub (maybe more like a switch) is pretty dumb with some minimal smarts.


The Dumb


The hub listens on a port for connections from interested modules.  Once connected the hub relays events to all connected modules (yes even back to the module that fired the event - the handler may be there too!).  Nice and dumb.


The Smart


Cry not for our poor hub.  It also has some basic smarts.  The smarts are necessary for 2 separate reasons:


1. sessions
2. trust


Sessions


Each connection to the hub is associated with a session, not an entire session, just a unique identifier.  This identifier, hmmm... identifies a session uniquely.  Didn't I just say that?  Anyway the hub itself does not use the session key, but merely passes it along to 'trusted' modules.  'Trusted' modules can use this identifier to store data associated with this session if they so choose. 
The hub injects the session key into any event arguments before passing the event on to any 'trusted' connected modules.


Trust


Some connected modules are more special than others.  These are typically server-side listeners that do actual work, like updating a database or flipping switches in a nuclear reactor.  Not all modules are created equally.  We wouldn't want just anyone connecting to our hub and responding to the 'reactor:TurnOn' event now would we?  
So a module is 'trusted' by the hub if, upon connection, it provides a secret key shared only by trusted modules and the event hub.  
So what does a 'trusted' module get that a plain old untrusted one doesn't?
It gets 2 things, the session key and responder status.
The session key is mentioned above, it's just a unique key that identifies the event emitter.
'Responder status' means a trusted module gets to listen for certain events, and ONLY that ONE trusted module will be delivered that event.
FOR INSTANCE the 'user:add' event.
Without a trusted listener for that event the 'user:add' event will be broadcast to all modules.  So a 'bad guy' can connect to your event hub and listen for that event and when a good guy tries to create a user (including username and password in the event data) the bad guy will get it.
Even without a bad guy some events only want one listener.  What if I had three modules, trusted ones event, listening for the 'user:add' event?  They would all get the event, the first one would succeed (say by adding the user to the database) while the other 2 would fail, as the user now already exists.  Even worse what about events with callbacks?  The first callback would work and the next 2 callbacks would fail as the callback already happened.


SO events with callbacks can only have ONE listener.  Events that change stuff should only have ONE listener.  That ONE listener should be 'trusted'.


SO the event hub must support trusted modules AND the ability to have only ONE listener for an event.  And as an extra added bonus IF the module is trusted it gets the session key to boot.


Ok stay with me here just about done!  Here's how it all comes together:


Module <-> Event Hub Initialization


Clients, typically browsers or command line clients, connect to the event hub with no special privileges.  They can emit all the events they want, not knowing or caring about all of this 'trust' or 'session' stuff.
Server-side modules can connect to the event hub with a shared key giving them 'trusted' status.  These trusted modules can request to listen for events which they deem 'unicast' using event-listening syntax sugar.


Unicast Event to Trusted Listener


Ok everyone is connected to the hub now, now the user creates a new user and the client fires the 'user:add' event with the username and password.  This unbeknownst-to-the-client is a unicast event that ONLY gets sent to the one trusted server-side module that is listening for it.  This handler adds the user to the database and can either fire another event upon successful completion or use a callback to respond with the operation's status.


Event with Session Key


Great so we have created a new user, now that user wants to log in.  User fills in their username and password and a 'user:login' event is emitted.  The trusted unicast listener (doesn't have to be unicast in this case) gets the username & password & session key from the event hub and verifies the credentials against the database.  A match!  Now the listener would use the unique session key to create a session object in the database with the username of the authenticated user and again uses the callback or emits a 'user:loggedIn' event of its own to report status.


Great, now that user wants to change their password.  So the client fires a 'user:changePassword' (or 'user:updateUser' or whatever) event with the username, new password and the event hub adds in the session key before handing re-firing the event to the trusted listener (perhaps unicast).  The listener verifies the username in the event matches the username associate with the session key and if they match updates the password.  Finally it can either fire an event 'user:passwordUpdated' (or whatever) or use a callback to report back status.


Doesn't that all just make perfect sense??


So our event hub has sessions and trusted modules and unicast, everything else is just dumb event and callback passthru.


SSL


An event hub can operate just fine over SSL.  You will not get the pretty 'lock' or 'green' URL bar but all of your data can very easily be sent encrypted.




Coming up next: languages, implementations, and deployment - stay tuned!!

Event Listeners

Event Listeners

Get up to speed first:
Part 1: http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html
Part 2: http://randomgoo.blogspot.com/2012/02/events.html

Quick recap - Web 3.0 is two-way asynchronous programming - events on the way out and another event or a callback on the way back.

There is no special syntax or language features required to listen for and respond to events.  So listen up!

hub.on('user:add', function(params, callback) {
    var user = params.user
          , pass = params.pass
    ;


    // Do something interesting (probably throw more events to
    //     save off to the DB) & when done if no error:
    callback(null, { success: true });
});

That's really it, attach a function to an event - the first parameter will be an object and the second will be a callback.  Both parameters are optional.

Note these examples use Javascript but THAT OF COURSE IS NOT REQUIRED!

Not all events require a response!  It's all about the documentation and expectation - event listeners MUST supply some sort of documentation to emitters:

/**
 * @method user:add handler
 * @param user username
 * @param pass password
 * @param callback required - response will contain 'success' 
 *    true or false
 */

Something like that - exactly as you would document a method-based API.  This handler can just as easily throw a 'user:Added' event instead of a callback:

hub.fire('user:Added', { success: true, user: params.user });


Firing an event as a response is preferable if you can get away with it so everyone can know what just happened, especially if it was successful, to give other parts of your application knowledge of what is going on.  Sometimes you do not need any response - like logging.


And sometimes you need a specific response directly back to you, for instance state information.


That's it for this round - stay tuned for MUCH more!

Events

Before reading this please read part 1:
http://randomgoo.blogspot.com/2012/02/release-event-hub-web-30-introduction.html

Quick recap - Web 3.0 is two-way asynchronous programming - events on the way out and another event or a callback on the way back.

So let's look at the event side of Web 3.0.

Event Syntax

  • Events Must have a string name
  • Events Might have an optional JSON-able set of parameters.
  • Events Might have an optional callback.

Event Names


Event names are strings, probably namespaced, separated from the namespace with a colon ':'.  It could also be a good idea to put a version number in there too if ya like, this can help keep your code in sync.  Up to you, play with it.

Here are some good event names:

user:add
user:delete
user:update
user-1.0:add    # module versioned
user:add-1.0    # listener versionsed
session:create

Event Parameters


Event parameters are serialized as JSON text so no function pointers or other funny business.  Toss in there whatever you need.  An important key is a session key.

Event Callback

Providing an optional callback allows event listeners to respond directly, asynchronously, back to the event emitter with data just for it.  The callback function should accept two paramters, a possibly null error object (or string) and a (possibly null) object with data for the emitter.

Check it:

hub.emit('user:add', { username: 'foobie', password: 'bloobie' },
    function(error, resp) {
        if (!error) {
            // sweet
        } else {
            // no dice
        }
    }
);

Look ma - no dependency on a 'user' object!

Event Semantics

Events are prayers that we expect to be answered.  It's possible they don't get answered.  What happens when events do not get answered?  Life goes on.

We'll look at event listeners next time...
(and still to come: the event hub itself, programming languages, and an implementation and experimentation)

Release The Event Hub: Web 3.0 - An Introduction

There are 2 factors of utmost import when coding: size and isolation.  While they both impact each other they are not the same.

Small code has fewer bugs.  Isolatable code has fewer dependencies and is easier to maintain.  So maintable code with few bugs, sign me up for that!

Small code is hard to write because code tends to get bound up in all the other code around it, despite our best efforts.

Especially over time feature creep and bug fixes tend to litter our once small code.  Plus it's just darn simpler at that moment to add code to already existing code instead of starting fresh.  So code grows and grows and without serious discipline that we all lack it never shrinks.

Isolatable code is hard to write because making everything an isolated unit is a giant pain in the ass.  There just is not any incentive day-to-day to write truly isolatable code.  If you do it still needs to be integrated into your application, why you are writing this code in the first place, and no one wants to keep doing that over and over again.  Besides have you ever seen an isolatable piece of
code?  Typically only the must mundane and obvious code is written as isolatable (or you're using 3rd party/open source code) - like obvious AOP stuff like logging and authentication.  Even then authentication is rarely isolatable from the HTTP server.  Same with session management.  Add authorization and message routing to all of that too.  Finally pulling 'business logic' away from the
HTTP server is difficult too.

Dependency management has almost single-handedly destroyed code quality since our ancesctors first hacked code on clay tablets back in the 1960s.  Creating, storing, calling, and destroying foreign objects has led to some of the most unmaintainable, tightly coupled, fan-out-crazy, untestable, downright ugly code imaginable.

With one stroke we can get rid of dependency hell, tightly coupled code, and useless blocking - while enhancing scalability, testability, maintainability, and code isolation.

Release The Event Hub!

Imgaine an army of independent handlers, each handler doing only one thing, communicating via only events and callbacks.  No external dependencies and no HTTP server requirement.  I'm talking about truly independent hunks of code 'Sofware as a Service' connected by an event hub.

Gone are the same-origin policy, HTTP servers routing messages, and tightly coupled code.

So how does it work?  Every independent module of code connects to a central event hub.  This hub can live on a separate host from your HTTP server and is actually a relatively simple piece of code.  It accepts connections from modules and passes emitted events to all connected listeners.  It also proxies callbacks back to the event emitter, is there is one (a callback, that is).

Event emitters connect to the hub and emit events and either:

1. are done
2. are listening for another event in response to theirs (or not)
3. wait for a callback from the listener

Event listeners connect to the hub and wait to service fired events.  In response they:

1. do nothing
2. fire another event
3. execute the provided callback

Of course a hunk of code can be both an event emitter and a listener.

OK that's enough for the first post - next up we'll look at how this actually all works (including sessions and security).  We will all miss multi-threading and method calls greatly: RIP.