Home > Net >  Better practice to send a message to Azure Event Hub with Serverless C# funcion
Better practice to send a message to Azure Event Hub with Serverless C# funcion

Time:06-25

This is my code...

namespaceMyNamespace
{
    public class Ping
    {
        private readonly ILogger<Ping2> _logger;
        public Ping2(ILogger<Ping2> log)
        {
            _logger = log;
        }
        [FunctionName("Ping2")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "v1/Ping")] HttpRequest req)
        {
            _logger.LogInformation("Processing: Ping");
            if (req.Query["agendaId"] == Microsoft.Extensions.Primitives.StringValues.Empty)
            {
                return new BadRequestResult();
            }
            Guid agendaId = Guid.Parse(req.Query["agendaId"]);
            string dataTag = "ZZZZ";
            string hubName = "myHub";
            EventHubProducerClient producerClient;
            producerClient = new EventHubProducerClient(connString, hubName);
            using EventDataBatch eventBatch = await producerClient.CreateBatchAsync();
            MensagemPing data = new MensagemPing() {
                ID = Guid.NewGuid(),
                agendaId = agendaId,
                dataTag = dataTag,
                timestamp = DateTime.Now
            };
            string jsonString = JsonSerializer.Serialize(data);
            eventBatch.TryAdd(new EventData(Encoding.UTF8.GetBytes(jsonString)));
            await producerClient.SendAsync(eventBatch);
            return new OkResult();
        }
    }
}

I can't find much documentation about the best way to implemment this. Just to start, I will never had a need to send a message in Batch. I found many examples about how to send a single message to the hub, but in mostly case, are deprecated examples or using classic asp.net application.

Also, this endpoint is taking one and a half second to be executed locally, specially because this snippet here take more than 1 second:

EventHubProducerClient producerClient;
producerClient = new EventHubProducerClient(connString, hubName);
using EventDataBatch eventBatch = await producerClient.CreateBatchAsync();
MensagemPing data = new MensagemPing() {
 ID = Guid.NewGuid(),
 agendaId = agendaId,
 dataTag = dataTag,
 timestamp = DateTime.Now
};
string jsonString = JsonSerializer.Serialize(data);
eventBatch.TryAdd(new EventData(Encoding.UTF8.GetBytes(jsonString)));

I am pretty convinced that this is not the best practice to consume event hubs. Maybe someone can give me some good example or maybe give me good hists about how to improve it and keep it more faster ?

CodePudding user response:

In this scenario, since you're using Azure Functions, you may want to consider using the Event Hubs output binding rather than using the client library directly. The benefit is that it manages the Event Hubs clients for you, including lifetimes and sending patterns.

If you decide to continue to use the client library directly, there are a few suggestions that I'd make:

  • The producer is intended to be long-lived; I'd strongly suggest creating it as a singleton, either by registering it via DI using the Microsoft.Extensions.Azure library (preferable) or by creating it as a static member of the class.

  • If you choose to continue creating the producer in the body of the Function, you'll need to close or dispose it. Otherwise, the connection that it owns will be left open until it idles out after ~20 minutes. This will eventually cause socket exhaustion on the host unless your traffic is really, really low.

  • Creating an explicit batch for a single event doesn't offer much benefit. I'd suggest using the SendAsync overload that accepts an enumerable instead. For example:

    await producer.SendAsync(new[] { eventData }, cancellationToken);
    
  • Not impactful, but if you'd like to simplify a bit, there's a constructor overload for EventData that accepts a string; no need to manually perform the encoding:

    var eventData = new EventData(jsonString);
    

If you're dealing with a higher call volume, it may be helpful to consider using the EventHubBufferedProducerClient, as it manages the building of batches and sends implicitly to try and maximize throughput. That said, using in a Functions context is awkward and requires more manual configuration in the Function startup in order to manage its lifetime properly and ensure events are flushed at cleanup. It's probably not worth it unless you're seeing a bottleneck on the single event sends, but there's an end-to-end sample that illustrates using it in an ASP.NET host, which is highly similar to Functions.

  • Related