I have an Azure function using a service bus trigger, created in C#.
This funcion recieves the service bus message (which contains a blob URL to a file), and calls an API, the API creates a DB record, then fills the DB record using the blob file and deletes it.
The API process may take up to 40 seconds.
After the API finishies, it sends a response to the azure function, which do "CompleteMessageAsync" or "DeadLetterMessageAsync" depending if the API response was positive or not.
The problem, based on seeing the DB records live, it creates multiple DB records and then start filling them simultaneously, even after I (supposedly) specified to run only one at a time. When it starts recieving the messages it goes one by one (as expected) but after just a few messages (6-7) it runs multiple messages at a time.
Depending on how much messages I send it either:
Note: There's only one function consuming this service bus queue, unless azure functions runs multiple instances without me knowing.
I tried completing the messages on my own, setting autocomplete to false, and setting "maxConcurrentCalls" to one, as well as "maxConcurrentSessions" to one as well just in case it´s necessary.
Function
public async Task Run(
[ServiceBusTrigger("serviceBus", Connection = "ServiceBusConnection", AutoCompleteMessages = false)]
ServiceBusReceivedMessage message,
ServiceBusMessageActions messageActions)
{
string content = message.Body.ToString();
try
{
//Send content to EndPoint
RestClient client = new RestClient("endpoint");
RestRequest request = new RestRequest("requestendpoint", Method.Post);
request.AddQueryParameter("paramName", content);
RestResponse response = await client.ExecuteAsync(request);
if (response.IsSuccessful)
{
_logger.LogInformation($"Success");
await messageActions.CompleteMessageAsync(message);
}
else
{
var errorDetails = response.Content;
_logger.LogInformation($"Failed: {errorDetails}");
await messageActions.DeadLetterMessageAsync(message);
}
}
catch (Exception ex)
{
_logger.LogInformation($"Exception: {ex}");
await messageActions.DeadLetterMessageAsync(message);
}
}
Host file azure configuration
{
"version": "2.0",
"extensions": {
"serviceBus": {
"prefetchCount": 1,
"messageHandlerOptions": {
"autoComplete": false,
"maxConcurrentCalls": 1
},
"sessionHandlerOptions": {
"autoComplete": false,
"maxConcurrentSessions": 1
},
"batchOptions": {
"maxMessageCount": 1,
"autoComplete": false
}
}
}
}
Based on your configuration, each of your Azure Function instances is configured to process exactly one message at a time. If you're seeing concurrent work happening, it is because the Function application is scaling up to additional instances.
This is something controlled by the Functions runtime and which the Service Bus listener has no insight into nor influence over. To ensure that your application has a single instance running, you'd have to configure scaling.
More context and discussion can be found in Event Driven Scaling: limiting scale-out.