Not able to restart the custom edge module while using the inbuilt "RestartModule" direct method of $edgeAgent from custom iot edge module.
malavvakharia opened this issue · 14 comments
Expected Behavior:
We can restart the custom module by invoking the $edgeAgent "RestartModule" direct method.But as of now it will be giving the error.
Steps to Reproduce:
Provide a detailed set of steps to reproduce the bug.
-
I am using the .NET sdk for invoking the inbuilt direct method of $edgeAgent.(Note: Calling the inbuilt direct method from the custom module not from $edgeAgent itself.)
-
Code snippet (C#):
var DataAsJson = @"{
""schemaVersion"": ""1.0"",
""id"": ""edgemodule1""
}";
var methodRequest = new MethodRequest("RestartModule", Encoding.UTF8.GetBytes(DataAsJson), TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
var result = await _moduleClient.InvokeMethodAsync("DeviceId","$edgeAgent", methodRequest);
- After deploying the module when we invoking the direct method calls it will give the error as shown in image.
To invoke a method on a module you should use the ModuleClient
, from the picture seems you are using the DeviceClient.
To invoke a method on a module you should use the
ModuleClient
, from the picture seems you are using the DeviceClient.
Hello @rido-min ,
I am already using the module client. Maybe that's not the issue.
my apologies @malavvakharia
I'm able to reproduce the issue when invoking direct methods on $edgeAgent
, however I'm able to invoke methods in other modules, so I suspect this might a limitation for $edgeAgent
.
Let me review what's the expected behavior of $egeAgent
and I'll update this ticket.
Thanks,
Rido
#region Assembly Microsoft.Azure.Devices.Client, Version=1.42.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
_cancellationToken = cancellationToken;
MqttTransportSettings mqttSetting = new(TransportType.Mqtt_Tcp_Only);
ITransportSettings[] settings = { mqttSetting };
// Open a connection to the Edge runtime
_moduleClient = await ModuleClient.CreateFromEnvironmentAsync(settings);
// Reconnect is not implented because we'll let docker restart the process when the connection is lost
_moduleClient.SetConnectionStatusChangesHandler((status, reason) =>
_logger.LogWarning("Connection changed: Status: {status} Reason: {reason}", status, reason));
await _moduleClient.OpenAsync(cancellationToken);
_logger.LogInformation("IoT Hub module client initialized.");
var iotEdgeDeviceId = Environment.GetEnvironmentVariable("IOTEDGE_DEVICEID");
var echoResp = await _moduleClient.InvokeMethodAsync(iotEdgeDeviceId,
"module-sample", new MethodRequest("echo", Encoding.UTF8.GetBytes("\"hello\"")));
_logger.LogInformation("Response from module-sample {r} ", echoResp.ResultAsJson);
MethodRequest request = new(
"RestartModule",
Encoding.UTF8.GetBytes(JsonSerializer.Serialize(new
{
schemaVersion = "1.0",
id = "SimulatedTemperatureSensor"
})),
TimeSpan.FromSeconds(15),
TimeSpan.FromSeconds(5));
string moduleId = "%24edgeAgent";
_logger.LogInformation("Sending request to {d}-{m} method {n} with {p}", iotEdgeDeviceId, moduleId, request.Name, request.DataAsJson);
var response = await _moduleClient.InvokeMethodAsync(iotEdgeDeviceId!, moduleId, request, cancellationToken);
_logger.LogInformation("Response status: {status}, payload: {payload}", response.Status, response.ResultAsJson);
}
fails with
<4>EdgeAgentClient.ModuleBackgroundService[0] Connection changed: Status: Connected Reason: Connection_Ok
<6>EdgeAgentClient.ModuleBackgroundService[0] IoT Hub module client initialized.
<6>EdgeAgentClient.ModuleBackgroundService[0] Response from module-sample "hellohello"
<6>EdgeAgentClient.ModuleBackgroundService[0] Sending request to tr-gateway-%24edgeAgent method RestartModule with {"schemaVersion":"1.0","id":"SimulatedTemperatureSensor"}
<3>Microsoft.Extensions.Hosting.Internal.Host[9] BackgroundService failed Microsoft.Azure.Devices.Client.Exceptions.DeviceNotFoundException: Device {"message":"Client tr-gateway/$edgeAgent not found"} not registered at Microsoft.Azure.Devices.Client.Transport.HttpClientHelper.ExecuteAsync(HttpMethod httpMethod, Uri requestUri, Func`3 modifyRequestMessageAsync, Func`2 isSuccessful, Func`3 processResponseMessageAsync, IDictionary`2 errorMappingOverrides, CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.HttpClientHelper.PostAsync[T1,T2](Uri requestUri, T1 entity, IDictionary`2 errorMappingOverrides, IDictionary`2 customHeaders, CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.HttpTransportHandler.InvokeMethodAsync(MethodInvokeRequest methodInvokeRequest, Uri uri, CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.ModuleClient.InvokeMethodAsync(Uri uri, MethodRequest methodRequest, CancellationToken cancellationToken) at EdgeAgentClient.ModuleBackgroundService.ExecuteAsync(CancellationToken cancellationToken) in C:\code\temp\EdgeAgentClient\ModuleBackgroundService.cs:line 55 at Microsoft.Extensions.Hosting.Internal.Host.TryExecuteBackgroundServiceAsync(BackgroundService backgroundService)
<2>Microsoft.Extensions.Hosting.Internal.Host[10] The HostOptions.BackgroundServiceExceptionBehavior is configured to StopHost. A BackgroundService has thrown an unhandled exception, and the IHost instance is stopping. To avoid this behavior, configure this to Ignore; however the BackgroundService will not be restarted. Microsoft.Azure.Devices.Client.Exceptions.DeviceNotFoundException: Device {"message":"Client tr-gateway/$edgeAgent not found"} not registered at Microsoft.Azure.Devices.Client.Transport.HttpClientHelper.ExecuteAsync(HttpMethod httpMethod, Uri requestUri, Func`3 modifyRequestMessageAsync, Func`2 isSuccessful, Func`3 processResponseMessageAsync, IDictionary`2 errorMappingOverrides, CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.HttpClientHelper.PostAsync[T1,T2](Uri requestUri, T1 entity, IDictionary`2 errorMappingOverrides, IDictionary`2 customHeaders, CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.HttpTransportHandler.InvokeMethodAsync(MethodInvokeRequest methodInvokeRequest, Uri uri, CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.ModuleClient.InvokeMethodAsync(Uri uri, MethodRequest methodRequest, CancellationToken cancellationToken) at EdgeAgentClient.ModuleBackgroundService.ExecuteAsync(CancellationToken cancellationToken) in C:\code\temp\EdgeAgentClient\ModuleBackgroundService.cs:line 55 at Microsoft.Extensions.Hosting.Internal.Host.TryExecuteBackgroundServiceAsync(BackgroundService backgroundService)
reported in Azure/iotedge#7116
This sample invokes a method on a device, but should be straight forward to update to use the overload that accepts the moduleId
This sample invokes a method on a device, but should be straight forward to update to use the overload that accepts the moduleId
That I have already tried just quick question here we have to pass which connection string here? (Custom module, $edgeAgentModule or Hub)
Reason I have already tried with the custom module connection string and as mentioned earlier It will give the authorization error.
If we have to use $edgeAgent connection string, then how to automatically fetch it in our custom module?
This sample invokes a method on a device, but should be straight forward to update to use the overload that accepts the moduleId
That I have already tried just quick question here we have to pass which connection string here? (Custom module, $edgeAgentModule or Hub)
Reason I have already tried with the custom module connection string and as mentioned earlier It will give the authorization error.
If we have to use $edgeAgent connection string, then how to automatically fetch it in our custom module?
@rido-min, Got the success but have just one doubt how to get the iot hub connection string from custom module environment variable? Do you have any idea?
For example, we get the device-Id like below:
string deviceId = Environment.GetEnvironmentVariable("IOTEDGE_DEVICEID");
the iothub connection string is not available for devices, you will need (not recommended) to include it in your module deployment.
the iothub connection string is not available for devices, you will need (not recommended) to include it in your module deployment.
@rido-min ,
Then that is not best practice how to set the connection string ?
you can include the connection string in the configuration of your module, or as environment variable, but again this is strongly discouraged.
I'd like to understand your use case.. Why do you need to restart a module from another module?
@malavvakharia
this is a not supported feature, is there anything else we can do to help? otherwise please consider closing this issue
@rido-min ,
I can close ticket but as you mentioned "you can include the connection string in the configuration of your module, or as environment variable, but again this is strongly discouraged."(#3373 (comment)) so how to handle this situation? As you say there is not any inbuilt environment variable to fetch the device connection string then how to do that?
Use case: Need to restart the custom module when any twin change detection found.
[please dont do this] you can add any string to the environment variables section in the deployManifest.json
.
I would try to avoid restarting the module, the SDK APIs should let you to observe any twin changes and process those without restarting
Agreed what you are saying regarding the restart module, in my use case I am using the broker details from twin and connect to it as well as use it's disconnect event to retry the connection now If I try to disconnect to that broker as twin changes it will try to retry the connection as per logic so In that case I have to restart the module or handle it on other way so it will not try to retry the connection again if that broker details removed from the twin.