androidazure-iot-sdk

When using Azure IoT SDKs for Java, do we need to handle device disconnections manually?


I am currently using Azure IoT SDKs for Java in our Android app.

It works fine and I'm able to connect, send messages and use the direct method callback without issue.

I found that if I turn off internet, the SDK DeviceClient automatically enters DISCONNECTED_RETRYING status, and when internet is back on, the status changes back to CONNECTED, which is great. However I encountered a few times where when I lock my phone screen for a while (to have lunch etc.) and reopen the app, I am still on the app and I didn't call client.close(), but when I try to send a message, it gives the error Cannot send event from a client that is closed. and seems like the status has changed to DISCONNECTED

Do we need to listen to connection status events and attempt to reconnect back ourselves? The client does seem to retry to connect back by its own, so I am not sure when is the time we need to write our own reconnect logic?

Thanks


Solution

  • The SDK does have some basic retry logic that will execute on its own whenever you lose connection. It uses an exponential backoff algorithm to decide how frequently to try to reconnect and, by default, will try for up to 4 minutes. In general, the default behavior isn't enough to stay "always connected".

    The first problem is that some disconnections last longer than 4 minutes. If the 4 minutes pass and the client fails to reconnect on its own, it will execute the connection status callback with status DISCONNECTED and stop retrying.

    For simpler cases you can alter the 4 minute timeout by calling

    deviceClient.setOperationTimeout(<new timeout value>);
    

    Beyond that, we recommend having some retry logic sitting on top of the device client as well to catch for unusual cases. We maintain some sample code of what we recommend in this regard.

    That sample code is pretty complex, and may be overkill for some scenarios, though. If your code is pretty simple, then you are fine just wrapping your sendEventAsync call in a while loop like

    DeviceClient deviceClient = new DeviceClient(...);
    deviceClient.setOperationTimeout(Long.MAX_VALUE)
    deviceClient.open(true);
    
    bool messageSent = false;
    while (!messageSent)
    {
        try
        {
            deviceClient.sendEventAsync(...);
            messageSent = true;
        }
        catch (IllegalStateException e)
        {
            // device needs to reconnect
            deviceClient.open(true);
        }
    }