Came across an inter­est­ing ques­tion on Stack­Over­flow on how one might be able to throt­tle the num­ber of requests across mul­ti­ple servers run­ning the same WCF ser­vice. So for instance, if you have 3 servers sit­ting behind a load bal­ancer and for one rea­son or another you can only allow 5 requests to be made against the ser­vice at any moment in time and any sub­se­quent requests need to be queued until one of the pre­vi­ous requests finish.

For those of you famil­iar with the pro­gram­ming con­cept of a sem­a­phore, you might see that the above require­ment describes a sem­a­phore which applies across mul­ti­ple machines. A quick search on Google for ‘cross-machine sem­a­phore’ reveals sev­eral imple­men­ta­tions of such sys­tem using memcached.

Nat­u­rally, a dis­trib­uted cache is a good way to go about imple­ment­ing a cross-machine sem­a­phore IF you are already using it for some­thing else. Oth­er­wise the over­head and cost of run­ning a dis­trib­uted cache clus­ter purely for the sake of a cross-machine sem­a­phore makes this approach a no-go for most of us..

Instead, you could eas­ily imple­ment a sem­a­phore ser­vice to pro­vide the same func­tion­al­ity to mul­ti­ple WCF clients as the bog-standard Sem­a­phore class do to mul­ti­ple threads. Such a ser­vice might look some­thing like this:

[ServiceContract]
public interface ISemaphorService
{
    [OperationContract]
    void Acquire();

    [OperationContract]
    void Release();
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class SemaphoreService
{
    private readonly static Semaphore Pool = new Semaphore(5, 5);

    public void Acquire()
    {
        Pool.WaitOne();
    }

    public void Release()
    {
        Pool.Release();
    }
}

This approach will intro­duce a sin­gle point of fail­ure as for sem­a­phore ser­vice to work cor­rectly it’ll need to be run­ning on a sin­gle machine. If you were to use this approach you should have build up some infra­struc­ture around it so that you can recover swiftly if and when the server run­ning the sem­a­phore ser­vice goes down.

In terms of the client code you should make sure that Release is called for every Acquire call, so would be a good idea to put a try-finally block around it:

var client = new SemaphoreServiceClient();

try
{
    // acquire the semaphore before processing the request
    client.Acquire();

    // process request
    ...
}
finally
{
    // always remember the release the semaphore
    client.Release();
}
Share

2 Responses to “WCF — Cross-machine semaphore with WCF

  1. offler says:

    That looks nice, but…

    I see some problems:

    1. which machine with peer to peer servers would be the sem­a­phore “server”?
    2. Net­work can go dead. finally won’t do alot with­out net­work connection.

  2. theburningmonk says:

    @offler -
    Regard­ing 1, if you have a net­work of peer-to-peer servers then you need to con­sider how sem­a­phores should be used, espe­cially if the peer-to-peer net­works are formed at a ad-hoc basis. Unless all the inde­pen­dent peer-to-peer net­work of nodes share the same pool of sem­a­phores, in which case a cen­tral­ized approach will still work.
    The above is just an out­line of an idea of imple­men­ta­tion using WCF, nowa­days Redis is so mature I would look into using Redis’s lists along with block­ing pop and push oper­a­tions instead.

    Regard­ing 2, if you’re going to use some form of shared sem­a­phores in a dis­trib­uted envi­ron­ment then you need to con­sider how your appli­ca­tion should han­dle net­work par­ti­tions.
    For instance, if a sub­set of the nodes lose con­nec­tiv­ity to the rest of the net­work, can/should the sys­tem con­tinue oper­at­ing in a soft-working state? Or can the sys­tem only func­tion if ALL of the nodes remain con­nected? In which case you might need to have heart­beat tests for all your nodes, etc.
    How (and if) to han­dle net­work par­ti­tions is a broader ques­tion that needs to be answered on a case-by-case basis, and not lim­ited to use of a cen­tral sem­a­phore server.

Leave a Reply