Im building an OO PHP application that will be run across multiple nodes, and will be relatively stateless in nature, and I need to implement proper publisher-subscriber (http://en.wikipedia.org/wiki/Observer_pattern / http://sourcemaking.com/design_patterns/Observer/php) style events.
My question is, how can I handle events?
In my application we are using technologies like Cassandra, Redis, Mongo and RabbitMQ.
I know PHP has an event EXTENSION available, but from what I can tell it sticks within state - or if something like memcached is leveraged it can possibly be used within that node... but my application will be distributed across multiple nodes.
So let's look at an example: On Node 1, a metric (Metric ID 37) is updated and anything that subscribes to that metric needs to be updated. This publishes Changing and Changed as it does the update.
I have something that is subscribed to Metric ID 37 being updated, for example Metric 38, may need to recalculate itself when Metric 37's value changes.
Metric 38 is currently instantiated and being used on Node 2 in Process ID 1011... How does Metric 37 tell Metric 38 on Node 2 (Process ID 1011 in this case) to run the subscribed function?
Metric 39 subscribes to Metric 38 being updated, but is not instantiated anywhere... How does Metric 39 update when Metric 38 finishes updating?
I was thinking of something like using RabbitMQ as my event queue manager, and on each node have a daemon style 'event consumer' application that reads events in the event queue (for sake of load balancing/distribution of the work).
Then the consumer sees "Metric:38:Updated" it checks something like Redis for anything subscribed to "Metric:38:Updated" and gets the value ("What:Function:Values") and does something like call_user_func_array(array($what,$function),$values); .... but this seems like it may cause a crapload of overhead and some level of synchronization issues...
I'm using Doctrine MongoDB ODM to persist my objects... To handle synchronization issues I was thinking of something like this: Objects could have a version number... (version=1.0) And redis could be used to maintain a quick reference to the latest version of the object (ObjectVersion:ObjectType:ObjectId)=1.1 And when a getter is called on an object property that is marked as @critical(things like isDeleted, monetary balances etc) it could check if the instance's version ID is equal to the version # in redis and update its values from mongo if it needs to...
An alternate setup is using amphp/amp
(http://amphp.org/docs/amp/reactor-concepts.html) and some form of RPC to synchronize the nodes
Since I'm fairly new to web development (moving from c#) and stateless, and distributed.. I thought it would be a good idea to ask the community if anyone has better suggestions?
My question is, how can I handle events?
If you want to use an event loop implementation, there are multiple choices available:
You can use a PubSub system like Redis offers: http://redis.io/topics/pubsub. Amp offers a package for Redis, other event libraries might already have an implementation available.
Redis will send an event notification to all connected and listening clients. You may not want that, because you want to synchronize your calculations and execute them only once.
You could push the actual data to a Redis list and use the event system only to poll in case of a new job, so the workers can otherwise sleep. A better solution might be to use blocking list operations, which block a Redis connection until there's new data available in a Redis list. When that event happens, you can recalculate the value and push the update to an event.
That's basically building a message queue with Redis, but essentially you will just want to look at the features of different message queue implementations and see if they suit your needs. If you want to use any of the event loop libraries, you may also want to look at the available clients and other features you need from them, because they're generally not compatible (yet).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With