Skip to main content

NServiceBus with Azure Functions turns 1.0

NServiceBus support for Microsoft Azure Functions, previously available as a preview package, is turning the big 1.0 and is now generally available.

Over the past nine months, we’ve been offering NServiceBus support for Microsoft Azure Functions as a Preview. This marked the first in a series of previews designed to provide new capabilities to the Particular Software Platform and explore new options for NServiceBus customers.

Now we’re adding Version 1.0 to its credentials, which means that in addition to production support, we’re also committing to all aspects of our support policy, including API stability and backporting of bug fixes. Plus we added a few more features, so you can do a lot more with Functions too.

Let’s take a look.

I was surprised by the simplicity of hosting an NServiceBus endpoint in an Azure Function. Now, when we rewrite our WebJobs to Functions we can drop our monthly costs by €10,000. Joey Chömpff, Software & Business Architect at Fudura

🔗Trusted in production

While in Preview status, we’ve had quite a few customers adopt NServiceBus with Azure Functions and run it in production.

This release would not have been possible without the trust from customers who adopted preview bits in real production systems and helped us to shape the product with features that matter to our cloud audience.

What’s in version 1.0? Every feature in the Preview and even a few new ones. Let’s take a look.

🔗Unified development model

After carefully reviewing how Functions are used in production, we found that most customers utilize Microsoft’s generic host approach when using Functions, configuring dependency injection and endpoints using IFunctionsHostBuilder. This is also called the class instance approach and differs from our original API that made the NServiceBus endpoint a static variable.

The class instance approach does everything that a static approach is capable of and enables a development model most customers are familiar with. For that reason, the static approach was removed and as of version 1.0 IFunctionsHostBuilder is the go-to development model for NServiceBus:

class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.UseNServiceBus(() =>
            new ServiceBusTriggeredEndpointConfiguration("MyFunctionsEndpoint"));
    }
}

🔗Transferable hosting

With the unified development model and generic-host-based Functions, the transition between various types of hosting on-premises and in Azure is a no-brainer. Endpoints hosted on-premises using the Generic Host use a similar configuration model as those hosted in Azure Functions.

When you’re mocking up a solution locally using the Learning Transport and the .NET generic host, it might look like this:

builder.UseNServiceBus(ctx =>
{
    var endpointConfig = new EndpointConfiguration("ConsoleEndpoint");
    endpointConfig.UseTransport(new LearningTransport());

    return endpointConfig;
});

This can easily be transferred to Azure Functions hosting using Azure Service Bus triggers:

builder.UseNServiceBus(() =>
{
    var endpointConfig =
        new ServiceBusTriggeredEndpointConfiguration("FunctionEndpoint");

    return endpointConfig;
});

🔗.NET ecosystem alignment

NServiceBus with Azure Functions is aligned with Microsoft dependency injection and registration conventions used by popular Microsoft and 3rd-party libraries. This creates a standard way to register components and services to be injected into NServiceBus handlers:

// Entity Framework Core
builder.Services.AddDbContext<ApplicationDbContext>(options =>
  options.UseSqlServer("<connection-string>"));

// Serilog
builder.Services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog());

// AutoMapper
builder.services.AddAutoMapper(profileAssembly);

🔗Support for all trigger types

Instead of just supporting queue-triggered functions, the 1.0 package supports all trigger types.

This means you can use virtually all Microsoft-provided bindings and custom triggers with NServiceBus.

That opens up a lot of new possibilities. To get an idea of what’s possible, let’s consider two use cases: reliable HTTP endpoints and a cloud scheduler.

🔗Reliable HTTP endpoints

Azure Functions are an easy way to build and scale HTTP endpoints. With NServiceBus support, these HTTP-triggered Functions can be made more reliable by converting incoming HTTP payloads into durable messages. The API immediately returns HTTP 202 Accepted, while the payload is forwarded as a durable message that can be retried if processing fails.

public class HttpTriggeredFunction
{
    public HttpSender(IFunctionEndpoint functionEndpoint)
    {
        this.functionEndpoint = functionEndpoint;
    }

    [FunctionName("HttpTriggeredFunction")]
    public async Task<IActionResult> RunAsync(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
        HttpRequest request, 
        ExecutionContext executionContext, 
        ILogger logger)
    {
        var sendOptions = new SendOptions();
        sendOptions.RouteToThisEndpoint();

        await functionEndpoint.Send(new TriggerMessage(), sendOptions, executionContext, logger);

        return new StatusCodeResult(StatusCodes.Status202Accepted);
    }

    readonly IFunctionEndpoint functionEndpoint;
}

🔗Cloud scheduler

With Functions’ dynamically scaling physical instances of the software are constantly being spun up and spun back down, which would normally be a nightmare for anything that needed to be orchestrated on a schedule. The TimerTrigger helps to ensure that only a single instance is running and executing at any time, no matter how many instances of a Function exist at the time of execution. Combining this trigger with NServiceBus enables a cloud-friendly scheduler to dispatch messages at given time intervals.

public class UserStorageChangesTracker
{
    public UserStorageChangesTracker(IFunctionEndpoint functionEndpoint, IMdcDbContext dbContext)
    {
        _functionEndpoint = functionEndpoint;
    }

    // Schedule: Execute every 6 hours
    [FunctionName(nameof(UserStorageChangesTracker))]
    public async Task RunAsync(
        [TimerTrigger("0 0 */6 * * *")] TimerInfo myTimer,
        ExecutionContext executionContext,
        ILogger logger)
    {
        await functionEndpoint.Publish(new PerformCleanup(), executionContext, logger);
    }

    private readonly IFunctionEndpoint _functionEndpoint;
}

🔗The future of Functions and NServiceBus

Version 1.0 of Azure Functions with NServiceBus targets the Microsoft.NET.Sdk.Functions SDK. This is well-established and trusted in production.

However, change is on the horizon at Microsoft. They have announced a new SDK, Microsoft.Azure.Functions.Worker. The new SDK is decoupled from the underlying Azure SDKs and is executed as a standalone process, solving various problems associated with the current SDK.

Soon we will add support for the new SDK in a brand new package. We’ll maintain both versions of interacting with Azure Functions as long as Microsoft supports the old SDK. We’ll also make sure that transitioning your NServiceBus Functions endpoints to the new SDK will be as easy as possible. Let us know if you’re interested in the new Functions SDK support.

🔗Summary

To get started with NServiceBus on Azure Functions, you just need to install the package:

Install-Package NServiceBus.AzureFunctions.InProcess.ServiceBus -Version 1.0.0

With full support for Azure Functions, we are bringing the Particular Service Platform to the cost-efficient serverless environment in Azure. The NServiceBus development model enables you to focus on coding the business logic, while we take care of the boilerplate Functions infrastructure code, handling serialization, routing, error handling, recoverability, and other complexities of messaging in distributed systems.

For more information, check out Hosting NServiceBus with Azure Functions in our documentation. You can also check out our recent webinar, Reports from the Field - Azure Functions in Practice.

Share on Twitter

About the authors

Sean Feldman

Sean Feldman likes tinkering with various Azure-related services and is in seventh heaven when cloud and distributed technologies are combined. When he's away from his computer and back on planet earth, he's having fun with family and his Malamute.

Yves Goeleven

Yves Goeleven, sometimes called the Cloudy Belgian, specializes in designing complex cloud applications based on web standards and messaging.

Don't miss a thing. Sign up today and we'll send you an email when new posts come out.
Thank you for subscribing. We'll be in touch soon.
 
We collect and use this information in accordance with our privacy policy.