Custom Azure Functions triggers

Component: NServiceBus.AzureFunctions.InProcess.ServiceBus
NuGet Package NServiceBus.AzureFunctions.InProcess.ServiceBus (2-pre)
Target NServiceBus Version: 8.x
This page targets a pre-release version. Pre-releases are subject to change and samples are not guaranteed to be fully functional.

If the trigger function must be customized, disable generation of the trigger function by removing the NServiceBusTriggerFunction attribute. A custom trigger function can then be added manually to the project:

class CustomTriggerDefinition
{
    IFunctionEndpoint functionEndpoint;

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

    [FunctionName("MyCustomTrigger")]
    public async Task Run(
        [ServiceBusTrigger("MyFunctionsEndpoint")]
        Message message,
        ILogger logger,
        MessageReceiver messageReceiver,
        ExecutionContext executionContext,
        CancellationToken cancellationToken)
    {
        await functionEndpoint.Process(message, executionContext, messageReceiver, logger, cancellationToken);
    }
}

Configuring transaction mode

If the NServiceBusTriggerFunction attribute is not used, IFunctionEndpoint.Process will determine the transaction mode based on the ServiceBusTrigger's AutoComplete property:

If auto-complete is enabled, which is the default, NServiceBus can't control the receive transaction and the message is processed in TransportTransactionMode.ReceiveOnly mode.

[FunctionName("ProcessMessage")]
public async Task Run(
    // Setting AutoComplete to true (the default) processes the message non-transactionally
    [ServiceBusTrigger("ProcessMessage", AutoComplete = true)]
    Message message,
    ILogger logger,
    MessageReceiver messageReceiver,
    ExecutionContext executionContext,
    CancellationToken cancellationToken)
{
    await endpoint.Process(message, executionContext, messageReceiver, logger, cancellationToken);
}

If auto-complete is disabled, NServiceBus can fully control incoming and outgoing messages and the message is processed in TransportTransactionMode.SendsAtomicWithReceive mode.

[FunctionName("ProcessMessageTx")]
public async Task RunTx(
    // Setting AutoComplete to false processes the message transactionally
    [ServiceBusTrigger("ProcessMessageTx", AutoComplete = false)]
    Message message,
    ILogger logger,
    MessageReceiver messageReceiver,
    ExecutionContext executionContext,
    CancellationToken cancellationToken)
{
    await endpoint.Process(message, executionContext, messageReceiver, logger, cancellationToken);
}

If additional control is needed, or the service bus trigger is not configured using an attribute, use the concrete FunctionEndpoint class:

class MyFunctions
{
    const bool EnableTransactions = true;

    // NOTE: Use concrete class instead of interface
    readonly FunctionEndpoint endpoint;

    public MyFunctions(FunctionEndpoint endpoint)
    {
        this.endpoint = endpoint;
    }

    [FunctionName("ProcessMessages")]
    public async Task Run(
        [ServiceBusTrigger("ProcessMessages", AutoComplete = !EnableTransactions)]
        Message message,
        ILogger logger,
        MessageReceiver messageReceiver,
        ExecutionContext executionContext,
        CancellationToken cancellationToken)
    {
        if(EnableTransactions)
        {
            await endpoint.ProcessTransactional(message, executionContext, messageReceiver, logger, cancellationToken);
        }
        else
        {
            await endpoint.ProcessNonTransactional(message, executionContext, messageReceiver, logger, cancellationToken);
        }
    }
}
Incorrectly configuring the service bus trigger auto-complete setting can lead to message loss. Use the auto-detection mechanism on the function endpoint interface, or use the trigger function attribute to specify message consistency.

Related Articles


Last modified