2006-01-24
Observers, Erlang and Server Push
As I've mentioned previously, I'm working on a framework for pushing events from an Erlang based web server to browser based clients using AJAX. My goal being to make it look like normal Erlang message sends to 'processes' running on the browser.
I have a server process that needs to broadcast events to interested parties whenever something of interest happens. My first thought was that this is the classic Observer pattern in OO style frameworks. I wanted other processes to be able to register with the server and they would then receive the notification. They can then later unregister when no longer interested in the data.
This turns out to be very easy in Erlang. A simple process to handle this looks something like:
notifier(Observers) ->
receive
{notify, Message} ->
lists:foreach(fun(To) ->
To ! Message
end,
Observers),
notifier(Observers);
{register, Observer} ->
notifier([Observer|Observers]);
{unregister, Observer} ->
notifier(lists:delete(Observer, Observers))
end.
Given a notifier, observers can register their interest in events. A server then sends a 'notify' message to the notifier, passing it the required data. This is in turn sent to all currently registered observers. So something like:
test() ->
receive
X ->
io:format("Received ~p~n", [X]),
test()
end.
Changes = spawn(module, notifier, [[]]).
Observer1 = spawn(module, test, []).
Changes ! {register, Observer1}.
Changes ! {notify, "Hello Message!"}.
...observer1 will output 'Received Hello Message!'...
Changes! {unregister, Observer1}.
Using code similar to this I created a notifier for my data source, and the observers are my HTML web pages. This is easy since I'm modelling each active page as a process. When an event occurs, the HTML on all displayed web pages are updated immediately using the AJAX based server push.