I have a function app that we are upgrading from the In-Process Model to the Isolated Worker Model.
Below I have a dumbed-down, pseudocode version of what I am working on with the relevant method signature and call.
[FunctionName("DummyFunctionName")]
public async Task RunDummyFunction([TimerTrigger("%DummyTrigger%")] TimerInfo timerInfo,[ServiceBus("%DummyQueue%", EntityType = ServiceBusEntityType.Queue, Connection = "DummyConnectionString")] IAsyncCollector<string> queue)
{
await _manager.DoStuff(queue);
}
We are passing the IAsyncCollector to the _manager.DoStuff. In that method, it will eventually call await queue.AddAsync(n1) where n1 is an IEnumerable string.
With the upgrades to the isolated worker model, I am unable get that IAsyncCollector anymore and pass it to the function.
I know I can decorate an object with the ServiceBus and return the object, but that is not going to return a Task in _manager.DoStuff. For example, we cannot do what it says in this article: https://weblogs.asp.net/sfeldman/functions-isolated-worker-sending-multiple-messages because it doesn’t return a Task.
This might be helpful too: https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus-output?tabs=python-v2%2Cisolated-process%2Cnodejs-v4%2Cextensionv5&pivots=programming-language-csharp#example
Please advise! Thank you!
2
Answers
In Isolated Model you cannot use
IAsyncCollector
but you can use service bus clients to send messages as below:Output:
Summary
(Following on from my comment)
Seeing as you already have a Service class, I’d be tempted to ditch the Function bindings entirely and instead use a Repository pattery. So, make the service take a repository interface representing the queue output, and then inject an implementation based on Service Bus. Here’s how.
1. Create an abstraction for Service Bus
Ignore that it’s Service Bus for now, and just create your own interface that represents a queue. Maybe put the interface in the same project as your Service.
(this will be useful if you want to Unit Test your Manager class too, as we’ll see later.)
2. Change your Manager class to use the
IQueue
abstractionYour Manager class now takes an
IQueue
object in the Constructor, and theDoStuff
method no longer requires any parameters:3. Write an
IQueue
implementation that uses Service BusThis takes a Constructor parameter of
ServiceBusClient
(which we will wire-up in the Dependency Injection config later.)Obviously you’ll want to pass through any config etc for the queue names.
Note, you might want to create a new Project to put this implementation in, so that you can keep the Service Bus dependencies separate from your Services or your Function App.
4. Wire up the above classes in Dependency Injection
This is for a .NET 8 Isolated Function using the latest (at time of recording…) ASP.NET Core style of Function App. Merge this with any other Dependency Injection config that you need to do.
Other bonuses
Unit Testing
Because your Manager class doesn’t need any Service Bus (or Azure Functions) specific types, you can Unit Test the behaviour by just mocking the
IQueue
implementation with something else.Batch queueing
If you want to send all your items at once, you can just modify or extend the
IQueue
implementation accordingly. For example:and:
and change your Manager class accordingly:
Hope that’s helpful!