Home > Back-end >  Azure Function App - Adding and Raising Event Handler C#
Azure Function App - Adding and Raising Event Handler C#

Time:12-21

I've got a question regarding Azure Function App (FA) using C#. I know Azure FA can be triggered by Azure Service Bus (SB) topic, but I've got some requirement that needs time triggered FA to read Azure SB topic message every time the FA triggered. As per Microsoft documentation stated here, we need to implement event handler. The problem is, the event not triggered when the FA is running. Is it possible or not for FA to raising event every time the FA running?

Here is my code:

using Azure.Messaging.ServiceBus;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace FA.Timer.Queue
{
    public class FuncTimerAla
    {
        private readonly ILogger _logger;

        public FuncTimerAla(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger<FuncTimerAla>();
        }

        [Function("FuncTimerAla")]
        public async Task Run([TimerTrigger("*/5 * * * * *")] MyInfo myTimer)
        {
            ServiceBusClient client;
            ServiceBusProcessor processor;

            client = new ServiceBusClient("[CONNECTION_STRING]");
            processor = client.CreateProcessor("[TOPIC_NAME]", "[SUBSCRIPTION_NAME]", new ServiceBusProcessorOptions());

            _logger.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");

            try
            {
                processor.ProcessMessageAsync  = MessageHandler;
                processor.ProcessErrorAsync  = ErrorHandler;

                await processor.StartProcessingAsync();
                _logger.LogInformation($"Wait for a minute and then press any key to end the processor");

                _logger.LogInformation($"Stopping the receiver...");
                await processor.StopProcessingAsync();
                _logger.LogInformation($"Stopped receiving messages");
            }
            catch (Exception ex)
            {
                await processor.DisposeAsync();
                await client.DisposeAsync();
            }
        }

        public async Task MessageHandler(ProcessMessageEventArgs args)
        {
            string body = args.Message.Body.ToString();
            _logger.LogInformation($"Received: {body}");
            await args.CompleteMessageAsync(args.Message);
        }

        public Task ErrorHandler(ProcessErrorEventArgs args)
        {
            Console.WriteLine(args.Exception.ToString());
            return Task.CompletedTask;
        }
    }

    public class MyInfo
    {
        public MyScheduleStatus ScheduleStatus { get; set; }

        public bool IsPastDue { get; set; }
    }

    public class MyScheduleStatus
    {
        public DateTime Last { get; set; }

        public DateTime Next { get; set; }

        public DateTime LastUpdated { get; set; }
    }
}

I am using .NET 6 to create isolated FA that published on Azure Service App. I've already try the sample code on console apps and it's running perfectly.
Thank you.

CodePudding user response:


As per @SeanFeldman explaination, the code wont execute the event handler delegate since on the sample code [here][1], there is a ReadKey() after start processing. By that sample, I add some thread sleep to give the processor enough time to read Service Bus topic message. Here is my final sample code:
using Azure.Messaging.ServiceBus;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace FA.Timer.Queue
{
    public class FuncTimerAla
    {
        private readonly ILogger _logger;
        
        public FuncTimerAla(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger<FuncTimerAla>();
        }

        [Function("FuncTimerAla")]
        public async Task Run([TimerTrigger("*/5 * * * * *")] MyInfo myTimer)
        {
            ServiceBusClient client;
            ServiceBusProcessor processor;

            client = new ServiceBusClient("[CONNECTION_STRING]");
            processor = client.CreateProcessor("[TOPIC_NAME]", "[SUBSCRIPTION_NAME]", new ServiceBusProcessorOptions());

            _logger.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");

            try
            {
                processor.ProcessMessageAsync  = MessageHandler;
                processor.ProcessErrorAsync  = ErrorHandler;

                await processor.StartProcessingAsync();
                _logger.LogInformation($"Wait for a minute and then press any key to end the processor");
                Thread.Sleep(5000);

                _logger.LogInformation($"Stopping the receiver...");
                await processor.StopProcessingAsync();
                _logger.LogInformation($"Stopped receiving messages");
            }
            catch (Exception ex)
            {
                await processor.DisposeAsync();
                await client.DisposeAsync();
            }
        }

        public async Task MessageHandler(ProcessMessageEventArgs args)
        {
            string body = args.Message.Body.ToString();
            _logger.LogInformation($"Received: {body}");
            await args.CompleteMessageAsync(args.Message);
        }

        public Task ErrorHandler(ProcessErrorEventArgs args)
        {
            Console.WriteLine(args.Exception.ToString());
            return Task.CompletedTask;
        }
    }

    public class MyInfo
    {
        public MyScheduleStatus ScheduleStatus { get; set; }
        public bool IsPastDue { get; set; }
    }

    public class MyScheduleStatus
    {
        public DateTime Last { get; set; }
        public DateTime Next { get; set; }
        public DateTime LastUpdated { get; set; }
    }
}

CodePudding user response:

Have you realized that the lifetime of both the processor and the client are within the lifetime of the function? I do not agree on the design for this FA. I would rather have a 2 Functions instead of one. One function to be triggered based on a bus like you mentioned in your question. And the second function process all the staged messages. But I am not sure what is the justification for this requirement

"time triggered FA to read Azure SB topic message every time the FA triggered"

I oppose using Sleep to delay a function.

Best would be to consider durable functions, these are designed for longer execution and for waiting a longer time. I think they are better suited for your situation.

  • Related