Correlation Identifier Pattern with Azure Functions Middleware

2023, Sep 22

Identifying and resolving issues in distributed applications can pose significant challenges. The strategic utilization of correlation identifier pattern1 is essential for precise mapping of the application's entire flow, streamlining the troubleshooting process effectively. In this post, learn how to implement correlation identifiers in Azure Functions (Isolated mode) using Middleware.

The application

In the context of an API, the implementation operates such that when generating a response, a correlationId is included. There are two straightforward scenarios: firstly, if no correlationId is initially provided, the implementation adds one. Secondly, if a correlationId is already provided, the implementation returns the same correlationId in the response.

Scenarios

As an example, the Function is a Http triggered endpoint that returns a Hello World message.

The middleware

The middleware implements the interface IFunctionsWorkerMiddleware, which brings the method Invoke containing FunctionContext and FunctionExecutionDelegate in its signature.

What is implemented is basically a wrapper around await next(context);. The x-correlationId is a convention often used to name the header that carries the correlation identifier within an HTTP request or response. This header is a way to associate a specific request with subsequent related events or actions in a distributed system. It's a custom header prefixed with "X-" to indicate that it's non-standard but widely adopted.

CorrelationIdMiddleware.cs

public class CorrelationIdMiddleware : IFunctionsWorkerMiddleware
{
    public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
    {
        var requestData = await context.GetHttpRequestDataAsync();

        // find existing correlationId
        // otherwise create new correlationId
        var correlationId = requestData!.Headers.TryGetValues("x-correlationId", out var values)
            ? values.First()
            : Guid.NewGuid().ToString();

        // action executed
        await next(context);

        // set correlationId to response
        context.GetHttpResponseData()?.Headers.Add("x-correlationId", correlationId);
    }
}

The way of how this is hooked to Azure Functions is through the project initialisation on Program.cs.

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults(workerApplication =>
    {
        // Register custom middleware with the worker
        workerApplication.UseMiddleware<CorrelationIdMiddleware>();
    })
    .Build();

host.Run();

Testing the scenarios

For when the correlationId is not provided via header, a new x-correlationId is added to response:

Scenario-1

For when the correlationId is provided via header, the same x-correlationId remains on response:

Scenario-2

The sample code is available on PlayGoKids repository