1

I'm working on microservices (using Azure Function Apps) that contain ServiceBusTrigger-based Azure Functions that trigger when a message is inserted into a Service Bus Queue.

I'm trying to determine the best way of binding output values to multiple targets (e.g. CosmosDB and IoT Hub). Whether or not the method is marked as async will determine how I should approach this problem.

As far as I am aware, the way that you would typically handle output binding with an async function is by using the [return: ...] annotation; however, in my use case, I need to return two different values to two separate targets (e.g. CosmosDb and IoT Hub). I don't think that this is something that I can achieve with return value binding or output variable binding, since you can't have an out param with an async method and you can define multiple return values with the [return: ...] approach.

It would seem that my only option (if I went the async route) would be to manually invoke SDK methods in the Azure Function to call the services independent of any output values. I'm trying to avoid doing that, seeing as output binding is the preferred approach.

An observation that I have made when creating a brand new ServiceBusTrigger-based Azure Function is that the generated method signature is not marked as async by default.

This is different than an HttpTrigger, which is marked as async out-of-box.

Can someone help me understand the reasoning for this? What are the scaling implications associated with one vs. the other?

I understand in a traditional sense why you typically mark an HttpTrigger as async; however, I don't understand the reasoning as to why the ServiceBusTrigger is not async

I need to understand this bit before I can move on with solidifying my approach to outputs.

Brandon Avant
  • 659
  • 5
  • 21

1 Answers1

1

I don't think templates with/without async functions have any reasoning to them as such. And depending on your code, your function may be more efficient.
Read this thread for more details on async/await in functions.

As for your main question, you just have to bind to different objects for the CosmosDB and IoT Hub output bindings.

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace CosmosDBSamplesV2
{
    public static class WriteDocsIAsyncCollector
    {
        [FunctionName("WriteDocsIAsyncCollector")]
        public static async Task Run(
            [QueueTrigger("todoqueueforwritemulti")] ToDoItem[] toDoItemsIn,
            [CosmosDB(
                databaseName: "ToDoItems",
                collectionName: "Items",
                ConnectionStringSetting = "CosmosDBConnection")]
                IAsyncCollector<ToDoItem> toDoItemsOut,
            ILogger log)
        {
            log.LogInformation($"C# Queue trigger function processed {toDoItemsIn?.Length} items");

            foreach (ToDoItem toDoItem in toDoItemsIn)
            {
                log.LogInformation($"Description={toDoItem.Description}");
                await toDoItemsOut.AddAsync(toDoItem);
            }
        }
    }
}
[FunctionName("EH2EH")]
public static async Task Run(
    [EventHubTrigger("source", Connection = "EventHubConnectionAppSetting")] EventData[] events,
    [EventHub("dest", Connection = "EventHubConnectionAppSetting")]IAsyncCollector<string> outputEvents,
    ILogger log)
{
    foreach (EventData eventData in events)
    {
        // do some processing:
        var myProcessedEvent = DoSomething(eventData);

        // then send the message
        await outputEvents.AddAsync(JsonConvert.SerializeObject(myProcessedEvent));
    }
}
PramodValavala
  • 6,026
  • 1
  • 11
  • 30
  • I'm pretty sure that this is what I'm looking for. I am in the process of trying it out right now. I do think that I have some small changes (i.e. specificity around having a Cosmos output and an IoT Hub output) that will be necessary. I will share those changes later today for those who may need them later. – Brandon Avant May 07 '19 at 15:31
  • So a problem that I've run into is figuring out the EventHubConnectionAppSetting value that I should use. I can't use the Event Hubs compatible connection string shown in built-in endpoints, since that particular endpoint is meant for read-only purposes. Where would I find the connection string to associate with the output parameter, so that I can send messages out to IotHub? – Brandon Avant May 07 '19 at 21:11