Azure / azure-iot-sdk-csharp

A C# SDK for connecting devices to Microsoft Azure IoT services
Other
464 stars 493 forks source link

[Bug Report] ModuleClient.SetConnectionStatusChangesHandler does not catch network changes #3347

Closed dvdzmr closed 10 months ago

dvdzmr commented 1 year ago

Context

I'm running a custom iot module on a raspberry pi 3b.

Relevant version info: Dotnet 6 Microsoft.Azure.Devices.Client (Tested on versions 1.39, 1.41 and latest)

Description of the issue

I have a function in my code that connects to azure via the environmental variables, where I also set the transport type (tested on MQTT and AMQP), however after connecting the raspberry pi to wifi and having the module succesfully connect, any disconnects (by turning off the wifi, not simulated) does not spring into action are not caugth by the connection handler.

I also tested this using the DeviceClient instead of the ModuleClient, leaving everything else equal and the code works just fine. However other issues such as proper twin and direct method handling, using the environment to connect all would no longer function as expected.

Code snippet

_moduleClient = await ModuleClient.CreateFromEnvironmentAsync(TransportType.Amqp,ClientOptions);
_moduleClient.SetConnectionStatusChangesHandler(ConnectionStatusChangeHandlerAsync);
//Does not realize its disconnected.
_deviceClient = DeviceClient.CreateFromConnectionString("connectionstring");
_deviceClient.SetConnectionStatusChangesHandler(ConnectionStatusChangeHandlerAsync);```
//This works as expected; when the connection is lost within ~30 seconds or less it registers. 

Final comments

I presume this to be a bug, since the underlying code for both DeviceClient and ModuleClient for this function seem to be identical.

Update

I have tested a configuration where I used ModuleClient.CreateFromConnectionString instead, and after ~2-3 minutes it does indeed report a disconnect. After retesting using the ModuleClient.CreateFromEnvironmentAsync I once again saw the described issue of it never detecting it.

So I guess my comparison to DeviceClient wasnt entirely accurate, it seems to be an issue rather with something ModuleClient.CreateFromEnvironmentAsync does when it creates a connection?

uecasm commented 1 year ago

I'm not an expert, but as I understand it, the module environment connection string gets the module to connect to the local IotHub module (which acts as a gateway), not to the cloud hub. As such it will only lose connection if that module shuts down or restarts -- the wifi / cloud upstream connection is invisible to it.

timtay-microsoft commented 11 months ago

+1 to @uecasm 's point. If you are removing wi-fi, you should expect this callback to be executed eventually on a device/module that connects to the cloud. For modules that connect within the edge device, they won't lose connection.

The other part of this is that this connection status callback depends on the keep alive setting (mqtt and amqp). Smaller values on this setting will allow for faster detection of connection losses. By default, it may take a few minutes for a disconnect to be detected. The downside of smaller keep alive values is that it means more network traffic on your connection, so you'll have to strike a balance here.

MiraLak commented 10 months ago

I have the same issue: Dotnet 7 Microsoft.Azure.Devices.Client 1.42.0

Tried with _TransportType.Amqp_WebSocketOnly and _TransportType.Mqtt_WebSocket_Only_ settings.

The connection status change handler is never called when we enable/disable internet connection...

            var settings = new ITransportSettings[]
                {
                    new AmqpTransportSettings(TransportType.Amqp_WebSocket_Only),
                };
            edgeClient = ModuleClient.CreateFromEnvironmentAsync(settings).Result;
            edgeClient.OpenAsync().Wait();
            edgeClient.SetConnectionStatusChangesHandler((status, reason) =>
            {
                Logger.Information("*****Connection status changed to {Status} ({Reason})", status, reason);
            });
            edgeClient.SetDesiredPropertyUpdateCallbackAsync(HandleNewDesiredProperties, edgeClient).Wait();

Is there any update about this ticket? Thanks.

uecasm commented 10 months ago

As I said before, if you're using CreateFromEnvironment within an IoT module, it means the module is connecting to the local hub (not the cloud hub), so it will only get notifications if the local hub is disconnected (e.g. during reboot/upgrade). It will not be notified about loss of the cloud link, since that's a further step away. That's not a bug, that's intended.

I'm not sure if there is (or perhaps should be) another event that does report cloud status, but it's not that one.

rido-min commented 10 months ago

To test the reconnection flow for ModuleClient running in IoTEdge, you can restart the $edgeHub module, or configure the network in the docker container.

timtay-microsoft commented 10 months ago

I believe the original question has been answered, so I'll close this thread