Iotedge: [V2] Question: Best practices with azure iot edge module-to-module communication

Created on 21 Sep 2018  路  4Comments  路  Source: Azure/iotedge

Hi,

Are there some examples or best practices on how to implement module to module communication within an IoT Edge device with this GA ([V2]) of Azure IoT Edge runtime?

Thank you.

/Henrik

customer-reported iotedge

Most helpful comment

Hi all,

I addition to using direct methods, it's also possible for two modules to communicate directly with each other, bypassing the Edge Hub. The runtime, via Docker's networking capabilities, manages the DNS entries for each module (container). This allows one module to resolve the IP address of another module by its name.

For an example of this in action, you can follow the SQL tutorial here: https://docs.microsoft.com/en-us/azure/iot-edge/tutorial-store-data-sql-server. This tutorial uses a module to read data out of the Edge Hub and write it into another module hosting SQLServer using the SQLServer client SDK. This interaction with SQLServer does not use the Edge Hub for communicating.

All 4 comments

Hi @HenrichBach1
This is what I've been trying to figure out for some time now.

I figured that you have to use direct methods if you want a more dynamic flow. The routes for sending messages seems to be static.

I'm looking forward for responses from people that actually knows.

You can see my quest on getting this to work here:
StackOverflow question
Github issue #337

Hi @NoExitTV ,

Thank you for your pointers.

If I follow the description given in https://docs.microsoft.com/en-us/aspnet/core/tutorials/web-api-vsc?view=aspnetcore-2.1 to create a "standard" module created with the .NET version 2.1 framework (without the extra given code), and supply the receiver side with this:

```c#.net
static async Task Init()
{
AmqpTransportSettings amqpSetting = new AmqpTransportSettings(TransportType.Amqp_Tcp_Only);
ITransportSettings[] settings = { amqpSetting };

        // Open a connection to the Edge runtime
        ModuleClient ioTHubModuleClient = await ModuleClient.CreateFromEnvironmentAsync(settings);
        await ioTHubModuleClient.OpenAsync();
        Console.WriteLine("IoT Hub module client initialized.");

        // Register callback to be called when a message is received by the module
        await ioTHubModuleClient.SetInputMessageHandlerAsync("input1", PipeMessage, ioTHubModuleClient);

        // Register direct method in the module
        await ioTHubModuleClient.SetMethodHandlerAsync("MethodA", MethodA, ioTHubModuleClient);
    }

    /// <summary>
    /// </summary>
    static async Task<MethodResponse> MethodA(MethodRequest methodRequest, object moduleClient)
    {
        try 
        {
            ModuleClient ioTHubModuleClient = (ModuleClient) moduleClient;

            Console.WriteLine("MethodA: Received the request: " + methodRequest.DataAsJson);

            var response = new MethodResponse
                                ( result:Encoding.UTF8.GetBytes("{ \"Message\": \"Hello, too...\" }")
                                , status:(int) 200 /*HttpStatusCode.OK*/
                                );

            return response;               
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
            Console.WriteLine(ex.StackTrace);
            return await Task.FromResult(new MethodResponse(500));
        } 
    }
And the sender side with this:

```c#.net
        static async Task Init()
        {
            AmqpTransportSettings amqpSetting = new AmqpTransportSettings(TransportType.Amqp_Tcp_Only);
            ITransportSettings[] settings = { amqpSetting };

            // Open a connection to the Edge runtime
            ModuleClient ioTHubModuleClient = await ModuleClient.CreateFromEnvironmentAsync(settings);
            await ioTHubModuleClient.OpenAsync();
            Console.WriteLine("IoT Hub module client initialized.");

            // Register callback to be called when a message is received by the module
            await ioTHubModuleClient.SetInputMessageHandlerAsync("input1", PipeMessage, ioTHubModuleClient);

            // Sending a request to a method in module on a device...
            while(true)
            {
                try
                {
                    var deviceId = System.Environment.GetEnvironmentVariable("IOTEDGE_DEVICEID");
                    var moduleId = "storage";
                    var methodId = "MethodA";
                    MethodRequest request = new MethodRequest(methodId, Encoding.UTF8.GetBytes("{ \"Message\": \"Hello\" }"));

                    Console.WriteLine($"Invoking method " + methodId
                                         + " in module " + moduleId 
                                         + " on device " + deviceId 
                                         + " with request: " + request.DataAsJson);

                    var response = await ioTHubModuleClient.InvokeMethodAsync(deviceId, moduleId, request).ConfigureAwait(false);

                    Console.WriteLine($"Received response with status: {response.Status} with message: {response.ResultAsJson}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error invoking method {ex}");
                }

Then, I'm able to use (direct) methods between modules:

pi@raspberrypi:~ $ iotedge logs -f storageClient --tail 25
IoT Hub module client initialized.
Invoking method MethodA in module storage on device hebh-IoT-Edge-Rpi3B with request: { "Message": "Hello..." }
Received response with status: 200 with message: {"Message":"Hello, too..."}
^C
pi@raspberrypi:~ $ iotedge logs -f storage --tail 25
IoT Hub module client initialized.
MethodA: Received the request: {"Message":"Hello..."}
MethodA: Received the request: {"Message":"Hello..."}
^C
pi@raspberrypi:~ $

/Henrik

Hi all,

I addition to using direct methods, it's also possible for two modules to communicate directly with each other, bypassing the Edge Hub. The runtime, via Docker's networking capabilities, manages the DNS entries for each module (container). This allows one module to resolve the IP address of another module by its name.

For an example of this in action, you can follow the SQL tutorial here: https://docs.microsoft.com/en-us/azure/iot-edge/tutorial-store-data-sql-server. This tutorial uses a module to read data out of the Edge Hub and write it into another module hosting SQLServer using the SQLServer client SDK. This interaction with SQLServer does not use the Edge Hub for communicating.

I'm going to close this issue due to inactivity, but please feel free to reopen.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

emilm picture emilm  路  6Comments

josiahlaivins picture josiahlaivins  路  6Comments

ejectbutton picture ejectbutton  路  4Comments

Lexmark-pcarey picture Lexmark-pcarey  路  4Comments

alaendle picture alaendle  路  4Comments