Azure Functions with Azure Service Bus

Host NServiceBus endpoints with Azure Functions and Azure Service Bus triggers.

A known issue of Service Bus-triggered functions may cause over-provisioning when scheduled messages are present in the function's queue. This includes messages present in the queue due to delayed retries, delayed delivery, or saga timeouts.

Basic usage

Endpoint configuration

NServiceBus can be registered and configured on the host builder using the UseNServiceBus extension method in the startup class:

[assembly: FunctionsStartup(typeof(Startup))]
[assembly: NServiceBusTriggerFunction(Startup.EndpointName)]

class Startup : FunctionsStartup
{
    public const string EndpointName = "MyFunctionsEndpoint";

    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.UseNServiceBus(() => new ServiceBusTriggeredEndpointConfiguration(EndpointName));
    }
}

Additional configuration settings are retrieved from environment variables. See the configuration section for further details. All configuration settings can also be configured directly via code:

class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.UseNServiceBus(() =>
        {
            var configuration = new ServiceBusTriggeredEndpointConfiguration("MyFunctionsEndpoint");
            configuration.Transport.ConnectionString("functionConnectionString");
            return configuration;
        });
    }
}

Any services registered via the IFunctionsHostBuilder will be available to message handlers via dependency injection. The startup class must be declared via the FunctionStartup attribute: [assembly: FunctionsStartup(typeof(Startup))].

Azure Function queue trigger for NServiceBus

The Azure Function trigger for NServiceBus is auto-generated by specifying the logical endpoint name using a custom assembly attribute:

[assembly: NServiceBusTriggerFunction("MyFunctionsEndpoint")]

The attribute will generate the trigger function required for NServiceBus:

An invalid endpoint name will generate an NSBFUNC003 error with the message Endpoint name is invalid and cannot be used to generate trigger function.

Overriding the trigger function name

The trigger function name is auto-generated by default. To customize the function name, the NServiceBusTriggerFunction attribute can be provided with an additional parameter to set the function name:

[assembly: NServiceBusTriggerFunctionAttribute(EndpointName: "MyFunctionsEndpoint", TriggerFunctionName: "MyTriggerFunction")]
An invalid trigger function name will generate an NSBFUNC004 error with the message Trigger function name is invalid and cannot be used to generate trigger function.

Customizing triggers

The Azure Service Bus trigger can be declared manually instead of relying on the auto-generated trigger. See the article on custom Azure Functions triggers for more information.

Dispatching outside a message handler

Triggering a message using HTTP function:

public class HttpSender
{
    readonly IFunctionEndpoint functionEndpoint;

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

    [FunctionName("HttpSender")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest request, ExecutionContext executionContext, ILogger logger)
    {
        logger.LogInformation("C# HTTP trigger function received a request.");

        var sendOptions = new SendOptions();
        sendOptions.RouteToThisEndpoint();

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

        return new OkObjectResult($"{nameof(TriggerMessage)} sent.");
    }
}

Message consistency

NServiceBus can provide transactional consistency between incoming and outgoing messages:

[assembly: NServiceBusTriggerFunction("MyEndpoint", SendsAtomicWithReceive = true)]

This is equivalent to the SendsAtomicWithReceive transport transaction mode. By default, transactional consistency is disabled, providing the same transport guarantees as the ReceiveOnly transport transaction mode.

For more information on configuring message consistency using custom triggers, refer to the custom Azure Functions triggers documentation.

Configuration

ServiceBusTriggeredEndpointConfiguration loads certain configuration values from the Azure Function host environment in the following order:

  • IConfiguration passed in via the constructor
  • Environment variables
KeyValueNotes
AzureWebJobsServiceBusConnection string for the Azure ServiceBus namespace to connect toThis value is required for ServiceBusTriggerAttribute. An alternative key can be passed into the constructor.
ENDPOINT_NAMEThe name of the NServiceBus endpoint to hostA value can be provided directly to the constructor.
NSERVICEBUS_LICENSEThe NServiceBus licenseCan also be provided via serviceBusTriggeredEndpointConfig.EndpointConfiguration.License(...).
WEBSITE_SITE_NAMEThe name of the Azure Function app. Provided when hosting the function in Azure.Used to set the NServiceBus host identifier. Local machine name is used if not set.

For local development, use local.settings.json. In Azure, specify a Function setting using the environment variable as the key.

{
  "IsEncrypted": false,
  "Values": {
    ...
    "NSERVICEBUS_LICENSE": "<?xml version=\"1.0\" encoding=\"utf-8\"?><license id=\"1222e1d1-2222-4a46-b1c6-943c442ca710\" expiration=\"2113-11-30T00:00:00.0000000\" type=\"Standard\" LicenseType=\"Standard\" LicenseVersion=\"4.0\" MaxMessageThroughputPerSecond=\"Max\" WorkerThreads=\"Max\" AllowedNumberOfWorkerNodes=\"Max\">. . .</license>"
  }
}

Custom diagnostics

NServiceBus startup diagnostics are disabled by default when using Azure Functions. Diagnostics can be written to the logs via the following snippet:

public override void Configure(IFunctionsHostBuilder builder)
{
    builder.UseNServiceBus(() =>
    {
        var configuration = new ServiceBusTriggeredEndpointConfiguration("MyFunctionsEndpoint");
        configuration.LogDiagnostics();
        return configuration;
    });
}

Error queue

For recoverability to move the continuously failing messages to the error queue rather than to the Azure Service Bus dead-letter queue, the error queue must be created in advance and configured using the following API:

class EnableDiagnosticsOnStartup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.UseNServiceBus(() =>
        {
            var configuration = new ServiceBusTriggeredEndpointConfiguration("MyFunctionsEndpoint");
            configuration.AdvancedConfiguration.SendFailedMessagesTo("error");
            return configuration;
        });
    }
}

Known constraints and limitations

The Configuration API exposes NServiceBus transport configuration options via the configuration.Transport property to allow customization; however, not all of the options will be applicable to execution within Azure Functions.

Preparing the Azure Service Bus namespace

Function endpoints cannot create their own queues or other infrastructure in the Azure Service Bus namespace.

Use the asb-transport command line (CLI) tool to provision the entities in the namespace for the Function endpoint.

Creating the endpoint queue

asb-transport endpoint create <queue name>

See the full documentation for the asb-transport endpoint create command for more details.

If the asb-tranport command-line tool is not used to create the queue, it is recommended to set the MaxDeliveryCount setting to the maximum value.

Subscribing to events

asb-transport endpoint subscribe <queue name> <eventtype>

See the full documentation for the asb-transport endpoint subscribe command for more details.

Assembly scanning

Assembly scanning loads assemblies from two locations:

  • The bin directory of the Azure Functions application
  • The Azure Functions runtime directory

If the same assembly is present in both locations, an exception is thrown which prevents the endpoint from running. Contact Particular Software support for assistance.

Package requirements

NServiceBus.AzureFunctions.Worker.ServiceBus requires Visual Studio 2019 and .NET SDK version 5.0.300 or higher. Older versions of the .NET SDK might display the following warning which prevents the trigger definition from being auto-generated:

CSC : warning CS8032: An instance of analyzer NServiceBus.AzureFunctions.SourceGenerator.TriggerFunctionGenerator cannot be created from NServiceBus.AzureFunctions.SourceGenerator.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=3.10.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified..

Samples

Related Articles


Last modified