How to consume Telemetry Events from IotHub with AzureFunctions?

Science beginning of messaging era on Azure Platform we had two different options
to read events from EventHub:

First one is extremely simple and gives you possibility to read from dedicated consumer group and partitions. However, when you have to provide a stable highly performant solution, you will figure out that EventHubClient is only trivial foundation to build such a complex read process.
With that in mind, years ago Messaging Product Group shipped EventProcessorHost, which enables a read across multiple nodes.
By using of EventProcessorHost you can implement every possible scenario on top of EventHub and IotEndpoints.
Originally, messaging is evaluated out of ServiceBus to EventHub, when it comes to events, telemetry and Co.

Unfortunately in many simple scenarios the need for hosting of solution with EventHubClient and EventProcessorHost is mostly more complex than simle processing of events.
This is when Serverless Computing gets interesting and useful. Microsoft Azure Functions does support high-scale read of events from EventHub and IotHub
by using of EventHubTrigger

But it s not obvious how to use this approach to read events from IotHub. Nicole posted very interesting article, which shows how to use IotHub routing to route events from IotHub into EventHub, with the goal to consume them. But using of additional EventHub might be costly and routing degrade performance of IotHub.
It is nothing bad about that in general, but if your goal is the consume events from IotHub only, then you can do it.
To use IotHub with AzureFunction EventHubTrigger is not difficult, but it is not obvious wehen reading documentation.

You have to know that IotHub endpoint is not same as EventHub endpoint. Both support same messaging, but they are different.
For example, IotHub endpoint supports more protocols and more features than EventHub. To access EventHub endpoint behind IotHub, you would typically have to use different path as commonly done in EventHubClient and EventProcessorHost.

var client = 
EventHubClient.CreateFromConnectionString(connStr, "messages/events");

But you have to knw that many API around (for example .NET Core) does not support second argument Path, where you can specify "messages/events". The best example is Azure Functions.
For this reason, IotHub provides some kind of alias called "Event Hub Compatible Endpoint", which can be grabbed out in portal.

To do this login to azure portal, navigate to your IotHub and go to endpoints
21433_iothubendpoints

Then you will see following endpoints:
21443_iothubendpoints2

Select Events to navigate to next page:
21510_iothubendpoints4

Here you can typically configure telemetry relevant properties. In context of this article, we are interested on "EventHub compatible name" and "EventHub compatible endpoint".

To activate this in your azure function code you need to do two things:

  1. Add IotHub connection string to local.settings.json.
  2. Set correct event hub name in your function.

Add IotHub connection string

Open local.settings.json
Add "iothubconnstr" in the configuration file and paste EventHub compatible connection string as shown in green frame on bottom on the previous picture.

{
  "IsEncrypted": false,
  "Values": {
    "iothubconnstr":     "Endpoint=EVENTHUBCOMPATIBLEENDPOINT",
    "AzureWebJobsStorage": "DefaultEndpointsProtocol=...,
    "AzureWebJobsDashboard": "..."
  }
}

Add IotHub connection string

Now go to implementation of your function and paste on place of EVENTHUBCOMPATIBLENAME the value from green frame in previous picture.

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Azure.WebJobs.ServiceBus;

namespace FunctionAppReader
{
    public static class ReadDeviceData
    {
        [FunctionName("ReadDeviceData")]
        public static void Run([EventHubTrigger("**EVENTHUBCOMPATIBLENAME**", Connection = "iothubconnstr")]string myEventHubMessage, TraceWriter log)
        {
             log.Info($"C# Event Hub trigger function processed a message: {myEventHubMessage}");
        }
    }
}

comments powered by Disqus