I have multiple Azure service bus queues to write to. I must use output bindings. But this output binding cannot be returned to the function endpoints because of the way that the code is structured.
I have this class:
public class OutputBindings
{
[ServiceBusOutput("%Queue1%", Connection = "ConnnectionString1")]
public string Queue1 { get; set; }
[ServiceBusOutput("%Queue2%", Connection = "ConnnectionString2")]
public string Queue2 { get; set; }
}
that is in this Function App endpoint:
[Function("FunctionName")]
public async Task Run([ServiceBusTrigger("%TriggerQueue%", Connection = "ConnectionString")] string message)
{
OutputBindings ob = new OutputBindings()
{
Queue1 = message,
Queue2 = message
};
// do other stuff
{
This is a really dumbed down pseudocode of this. I cannot return the OutputBindings class. I need the messages to propagate to the two other queues the moment that they are set. Thanks.
It sounds like you're wanting to send messages to two different Service Bus queues, ideally simultaneously. Or rather accurately, with the minimum possible delay.
Here's one approach based on using ServiceBusClient
directly, injected by dependency injection. It's similar to the post I referred to in comments, but implementing it directly in the Function class you posted above rather than using a Service.
There are some caveats which I'll list at the end.
// Note the ServiceBusClient is injected from DI config.
public class YourFunctionClass(ServiceBusClient _sbClient)
{
[Function("FunctionName")]
public async Task Run([ServiceBusTrigger("%TriggerQueue%", Connection = "ConnectionString")] string message)
{
// Get each queue. Note these operations aren't long-running
// so there's no delay here.
var queue1 = _client.CreateSender("Queue1Name");
var queue2 = _client.CreateSender("Queue2Name");
// Create message content however you wish.
var message1 = new ServiceBusMessage(Queue1(message));
var message2 = new ServiceBusMessage(Queue2(message));
// Create async tasks for each enqueue operation.
// NB we aren't awaiting the tasks here, so
// there will be almost no delay executing these lines of code.
Task task1 = queue1.SendMessageAsync(message);
Task task2 = queue2.SendMessageAsync(message);
// Now both those enqueue operations are sent at the same time,
// and we wait until they're both completed.
await Task.WhenAll(task1, task2);
}
private string Queue1(string message) => message + "foo"; // your own logic
private string Queue2(string message) => message + "bar"; //
}
Note the key points:
And some relevant config in Program.cs
, for example:
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services =>
{
// Register the ServiceBusClient with DI.
services.AddAzureClients(configureClients =>
{
configureClients.AddServiceBusClient("DummyConnectionString");
});
// add your other services here too.
})
.Build();
host.Run();
You can't have a queue "already connected" as such. On the plus side, the CreateSender
call doesn't take any time at all, so you don't have to worry about connection time. On the down side, that's because you always have a delay when you do that actual enqueuing in SendMessageAsync
- ServiceBus is a cloud service, after all.
There's no such thing as "simultaneously" in a cloud context if you have two separate queues. You're firing the requests off at the same time, but there's no guarantee they will both be processed at the exact same time. Cloud is not deterministic in that way.
This is ignoring problems such as one queue succeeding but another one failing to enqueue. Or even that Queue2 trigger its processor before Queue1 has enqueued. You would really need some logic that handles such a situation. It'll need some try/catch
and accompanying logic here, and maybe also some logic in the queue processors. Probably you need to give us more detail about what the queue processors are doing at the other end.
It might be worth you explaining what the two queues are needed for, because perhaps there's a different architecture that would suit the problem. Perhaps avoiding the problem I described above, where one enqueue fails but another succeeds.
Hope that helps!