Adding headers and instrumentation to Service Fabric default comm. stack

Update

With Service Fabric SDK v2 this became much simpler. Check out this SO answer of mine for details.


Service Fabric’s default communication stack for Reliable Services provides a simple way to enable communications without worrying about protocols, discovery, and much more as we shall see. To use the stack, we need to create a ServiceRemotingListener, which implements ICommunicationListener, as well as create a service interface:

interface IMyService : IService
{
    Task<MyData> DoIt();
}

class MyService : StatelessService, IMyService
{
    protected override IEnumerable CreateServiceInstanceListeners()
    {
        return new[] { new ServiceInstanceListener(parameters => new ServiceRemotingListener(parameters, this)) };
    }

    public Task<MyData> DoIt()  
    {
        return Task.FromResult(new MyData());
    }
}

Then, to use the service, we can create a proxy using ServiceProxy:

var myService = ServiceProxy.Create<IMyService>();
await myService.DoIt();

However, what the stack doesn’t trivially provide are hooks for adding headers and instrumentation for the service operations. Headers are essential in modern SO architectures. They can allow ambient information such as identity to pass along messages. Instrumentation allows you to add code when a service operation starts and ends. This could be used for logging, error handling, authorization and more. In this post I will share a solution for adding both of these.

Get the code

This sample is no longer relevant with SDK v2 and has been removed

https://github.com/aelij/samples-servicefabric-instrumentation

How it works

In the latest preview, two additions were made to the service API that enable this – both ServiceRemotingListener and ServiceProxy now accept a factory that allows us to construct the “inner” communication listener and client. What does this mean? Both the listener and the proxy are higher level abstractions, and they use inner classes to provide the actual communication layer. By default, Service Fabric uses WCF. All of this implementation is internal, so in the sample code you’ll see a replica of that internal code with the added hooks.

The heart of the solution relies on the WcfRemotingService class, which is the implementation of the WCF service. This class receives generic messages, in the form of a byte array, later to be decoded and dispatched into our implementation (e.g. the MyService class above). So, essentially, we can add any code before and after the execution of the method.

Service Fabric uses the class ServiceRemotingMessageHeaders to send metadata about which interface and method were called. This data is encoded into integer hashes of the names. The sample code also shows how to decode this data for logging purposes. This could be very useful for other uses, such as extracting attributes from the methods, and applying policy according to them. In addition, we can add our own headers. In the sample, I’ve added the ClaimsIdentity of the client to the headers. I’m using a neat .NET 4.6 class called AsyncLocal<T> to allow the context to flow between awaits (note that 4.6 is not installed on Service Fabric clusters by default, and requires additional setup).

The other part of the solution is the client side, in the WcfServiceRemotingClient class. That is where we add the headers before sending requests to the server.

How to use it

In the sample code above, simply replace new ServiceRemotingListener with ServiceRemotingListenerEx.Create and ServiceProxy with ServiceProxyEx. This will enable the custom listener and client.