Erlang Pattern: The Router
Posted: October 19th, 2009 | Author: kevin | Filed under: Erlang | View CommentsThere are three components to this pattern. The client, the router, and the target. The client begins the process by calling the router with a message destined for a target. The router uses the message, and possibly other metadata, to locate a desirable target. Then the router hands off the message to the selected target. The target replies directly to the client and completes the process.
I’ve written this code a number of times in several different languages. What makes the Erlang implementation so nice is it’s brevity and simplicity. Using the gen_server behavior I can implement the core logic in just a few lines:
-
Client calls the router with a message destined for a target:
gen_server:call(?ROUTER, {invoke, Target, Msg}) -
The router looks up the target and forwards the message on:
handle_call({invoke, Target, Msg}, From, State) ->
%% Target selection code goes here
gen_server:cast(TargetPidOrName, {From, Msg}),
{noreply, State};
-
The target replies directly to the waiting client:
handle_cast({Originator, Msg}, State) ->
%% Server logic goes here
gen_server:reply(Originator, Reply),
{noreply, State};
The pretty bit is that all this plumbing can be hidden away inside a function. So the original call to the router in the client winds up looking like this: router:invoke_target(Target, Msg). The rest happens behind the scenes and appears as just another gen_server call.
I’m pretty sure there are no bugs in using this approach. I’ve benchmarked a recent implementation of this pattern at over 6000 requests/sec without a hiccup.