Open mikenerone opened 4 years ago
Ok, the cause is that in MQTTClient.disconnect()
, these two operation are effectively done in succession:
await self._handler.mqtt_disconnect()
...
await self._handler.stop()
The first call ends up queueing the disconnect packet for sending, but that is not actually complete when the stop()
ends up killing the handlers sender task. Here's a terrible workaround that actually works:
--- a/distmqtt/client.py
+++ b/distmqtt/client.py
@@ -262,6 +262,7 @@ class MQTTClient:
if self._disconnect_task is not None:
await self._disconnect_task.cancel()
await self._handler.mqtt_disconnect()
+ await anyio.sleep(0.1)
self._connected_state.clear()
await self._handler.stop()
self.session.transitions.disconnect()
But I think this needs a more proper fix than that that depends on a positive indicator of completion of sending the disconnect packet, but I'm not sure how you'd like to approach that (though I'm happy to help if you have a suggestion).
For now, out of necessity, I'm going to workaround the issue by monkey-patching ClientProtocolHandler.mqtt_disconnect()
to add a short sleep before returning.
Reproduction script (obviously, I had a broker set up listening on both of the URLs in this):
Running this without "secure" on the command line works fine, regardless of backend
But running it with
secure
on the command line (enabling MQTTS and using asyncio) crashes the app with a stack trace:Running it with "secure" and "trio" on the command line (enabling MQTSS and trio) also crashes with a stack trace, but it's different: