REST + Actors

I had a really good idea over the weekend for using eventlet and mulib to combine the concepts of REST and Actors. Eventlet has had an Actor class for a while now, but I haven't really used it for anything. After otakup0pe twittered a link to the Reia language (everyone knows how much of a language geek I am) I started thinking about Actors again and how I could have applied them to various work problems I solved in the last few years. The last time I really tried to do anything serious with Actors was when I wrote the latest version of Pavel on top of the just-written (at the time) eventlet. I also tried to mix a prototype object system in there and the actor coroutines were implicit in the semantics of usage (an Actor which called a method on another Actor would be implicitly causing a switch into the other Actor's coroutine), which in retrospect was perhaps a bit too ambitious.

Ryan Williams wrote the current eventlet Actor (eventlet.coros.Actor) and it's much simpler and more straightforward: You override the received method to handle messages, and other actors call the cast method to send messages. This is different from my previous implementation (and also what my ideal would be) in that you get called back for every message, meaning the main coroutine is generic and there's no need to keep track of where the Actor's coroutine is to serialize an actor. This means it would be possible to request a representation of an Actor at any time between messages. The state would include all the Python instance variables along with all the unhandled messages currently in the Actor's mailbox.

So, with that realization, it suddenly becomes trivial to write a mulib handler for the Actor class. GET and PUT with the appropriate content types (application/json for example) would get or set the current state of the Actor. DELETE would delete it. POST enqueues a message in the actor's mailbox (it just calls cast with the body of the request). Simple and straightforward. I'm totally going to do this soon -- it probably would have been faster to just do the implementation rather than blog about it :-)

Oh, one more thing -- to enhance the experience of actually using these semantics, the cast method should become a generic method that dispatches based on pattern matching (using mulib.shaped). I haven't figured out what an efficient implementation of this would look like yet, but I'm going to try a brute-force implementation just for fun.

No comments: