question

SatyamChauhan-7119 avatar image
0 Votes"
SatyamChauhan-7119 asked LeelaRajeshSayana-MSFT edited

How can we make asynchronous call to edge hub trigger from a C# edge module ?

The iot edge solution is having 2 modules, first module is a C# module and second is Edgehub trigger module. First module is sending data in a loop to second module. I want the edge hub module to execute asynchronously

         static async Task Main(string[] args)
                 {
                     _logger = Logger.Factory.CreateLogger<string>();
                     var moduleClient = await Init();
            
                     // Wait until the app unloads or is cancelled
                     var cts = new CancellationTokenSource();
                     AssemblyLoadContext.Default.Unloading += (ctx) => cts.Cancel();
                     Console.CancelKeyPress += (sender, cpe) => cts.Cancel();
            
                     while (!cts.Token)
                     {
                              HttpResponseMessage response = await client.GetAsync('https://abcd.com');
                              var stringResponse = await response.Content.ReadAsStringAsync();
            
                              var data = JObject.Parse(stringResponse);
                              await SendMessageToEdgeHubModule(moduleClient, data);
                                 
                              await Task.Delay(5000, cts.Token);
                     }
                     WhenCancelled(cts.Token).Wait();
                 }
    
 public static Task WhenCancelled(CancellationToken cancellationToken)
         {
             var tcs = new TaskCompletionSource<bool>();
             cancellationToken.Register(s => ((TaskCompletionSource<bool>)s).SetResult(true), tcs);
             return tcs.Task;
         }
        
     static async Task<ModuleClient> Init()
             {
                 AmqpTransportSettings amqpSetting = new AmqpTransportSettings(TransportType.Amqp_Tcp_Only);
                 ITransportSettings[] settings = { amqpSetting };
                 ModuleClient ioTHubModuleClient = await ModuleClient.CreateFromEnvironmentAsync(settings);
                 try
                 {
                     // Open a connection to the Edge runtime
                     await ioTHubModuleClient.OpenAsync();
                     _logger.LogInformation("IoT Hub module client initialized.");
                 }
                 catch (Exception ex)
                 {
                     _logger.LogCritical("Exception occured while initializing IoT Hub module client : " + ex);
                 }
                 return ioTHubModuleClient;
             }

.
I have tried -
1 -

 static async Task SendMessageToEdgeHubModule(ModuleClient ioTHubModuleClient, List<String> items)
 {  
         foreach(var item in items)
         {
                 var message = new Message(Encoding.ASCII.GetBytes(item));
                 await ioTHubModuleClient.SendEventAsync("output1", message);
         }
 }

2 -

 static async Task SendMessageToEdgeHubModule(ModuleClient ioTHubModuleClient, List<String> items)
     {
        
            await Task.Run(() =>
            {
                  items.ToList().ForEach(async item =>
                  {
                       var messageOut = new Message(Encoding.ASCII.GetBytes(item));
                       await ioTHubModuleClient.SendEventAsync("output1", messageOut);
                  }
            }
     }

3 -

 static async Task SendMessageToEdgeHubModule(ModuleClient ioTHubModuleClient, List<String> items)
     {
            await Parallel.ForEachAsync(items.ToList(), async (item, token) =>
            {
                     var messageOut = new Message(Encoding.ASCII.GetBytes(item));
                     await ioTHubModuleClient.SendEventAsync("output1", messageOut);
            }        
     }

All these methods are triggering the edgehub module sequentially.
Is there a way through which we call edge hub async.





azure-iot-edgeazure-iotdotnet-iot
· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @SatyamChauhan-7119 , thank you for posting the additional information requested.

Your main method does not have any parallel threads running in it. It is the main program thread working concurrently on different tasks. Code execution is pretty much linear till the point where you call the SendMessageToEdgeHubModule method inside the while loop. Within in the SendMessageToEdgeHubModule method, the call SendEventAsync is asynchronous. But since we are iterating over the list in all the three choices to make the SendEventAsync call, it is always going to be sequential.

Please note that the method SendEventAsync returns a Task and all the current approaches have await operator on it. So, the next call will wait till the first task is returned. To make is non waiting, you can remove the await keyword before you make the call to ioTHubModuleClient.SendEventAsync("output1", messageOut) in either the second or third approach.

A point to note is that this would still be a sequential call to the edge hub module. But now that we removed the await keyword, the program execution will not wait and proceed with making another call.

Please let me know if this clarifies and helps with what you are trying to achieve.

1 Vote 1 ·
SatyamChauhan-7119 avatar image SatyamChauhan-7119 LeelaRajeshSayana-MSFT ·

Hi @LeelaRajeshSayana-MSFT,
Thanks for answering,
I tried this by removing the await keyword from ioTHubModuleClient.SendEventAsync("output1", messageOut), but still edge hub starts triggering only after the ForEach and ForEachAsync loop ends.

0 Votes 0 ·
LeelaRajeshSayana-MSFT avatar image LeelaRajeshSayana-MSFT SatyamChauhan-7119 ·

Hi @SatyamChauhan-7119, apologies for the delayed update on this issue. I am still working on testing this from my end. Could you please confirm if your Edge hub trigger function is configured to receive events in a batch as opposed to individual events. You can validate this by verifying your edge hub trigger function function declaration and see if the EventData parameter is set to Array. Please refer the following example for more details. If the function is set to process events in batch, could you please change that to trigger per event and see if that makes any difference.

Could you also please let me know an estimated number of items we are iterating here? If the size is too small, we would not be able to tell if the call to edge hub trigger is asynchronous. To validate this let's add a pause after each call and observe when the edge hub trigger is called. Please refer the below code snippet.

                  ioTHubModuleClient.SendEventAsync("output1", message);
                  await Task.Delay(10000);

Please let us know if this is useful and kindly keep me posted on your findings.


0 Votes 0 ·

Hello @SatyamChauhan-7119 ,

Thank you for posting this question. We might need some additional information to better understand the issue here. Can you provide more details on the code snippet where this method, SendMessageToEdgeHubModule, is being called from?

0 Votes 0 ·

0 Answers