avoid InvalidStateError on disconnect #67
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
I have a python script with this library subscribed to two topics on a self-hosted mosquitto broker. Rebooting the router between the two caused the script to crash with an
InvalidStateError
inforce_disconnect()
(full stack trace below).I think this error happens because i have two coroutines with an
async for
waiting for messages from two separateclient.filtered_messages()
. One of them gets the error first and runs__aexit__()
and ends up callingforce_disconnect()
. When the second one gets there, the_disconnect
future already has a result andset_result()
causes theInvalidStateError
.__aexit__()
already has code to prevent this:However, this code is ineffective due to the
await
calls between the check andset_result()
. My pull request fixes this problem by introducing another check with noawait
between the check andset_result()
.Stack trace for InvalidStateError
``` Jun 27 17:13:54 lignin python3[132815]: DEBUG:send_serial:sent b'PC: light 0\n' Jun 27 17:14:48 lignin python3[132815]: WARNING:mqtt:Could not gracefully disconnect due to "Operation timed out". Forcing disconnection. Jun 27 17:14:48 lignin python3[132815]: ERROR:asyncio:Task exception was never retrieved Jun 27 17:14:48 lignin python3[132815]: future: Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/usr/lib/python3.9/asyncio/locks.py", line 226, in wait Jun 27 17:14:48 lignin python3[132815]: await fut Jun 27 17:14:48 lignin python3[132815]: asyncio.exceptions.CancelledError Jun 27 17:14:48 lignin python3[132815]: During handling of the above exception, another exception occurred: Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/usr/lib/python3.9/asyncio/tasks.py", line 492, in wait_for Jun 27 17:14:48 lignin python3[132815]: fut.result() Jun 27 17:14:48 lignin python3[132815]: asyncio.exceptions.CancelledError Jun 27 17:14:48 lignin python3[132815]: The above exception was the direct cause of the following exception: Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/venv/lib/python3.9/site-packages/asyncio_mqtt/client.py", line 337, i> Jun 27 17:14:48 lignin python3[132815]: return await asyncio.wait_for(fut, timeout=timeout, **kwargs) Jun 27 17:14:48 lignin python3[132815]: File "/usr/lib/python3.9/asyncio/tasks.py", line 494, in wait_for Jun 27 17:14:48 lignin python3[132815]: raise exceptions.TimeoutError() from exc Jun 27 17:14:48 lignin python3[132815]: asyncio.exceptions.TimeoutError Jun 27 17:14:48 lignin python3[132815]: During handling of the above exception, another exception occurred: Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/water_arduino.py", line 193, in read_until_failure Jun 27 17:14:48 lignin python3[132815]: await asyncio.gather(*tasks, return_exceptions=False) Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/water_arduino.py", line 187, in write Jun 27 17:14:48 lignin python3[132815]: await client.publish(topic, data) Jun 27 17:14:48 lignin python3[132815]: await client.publish(topic, data) Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/venv/lib/python3.9/site-packages/asyncio_mqtt/client.py", line 232, i> Jun 27 17:13:23 lignin python3[132815]: DEBUG:send_serial:sent b'PC: light 0\n' Jun 27 17:13:53 lignin python3[132815]: DEBUG:read_mqtt:received light msg: b'{"state": "ON", "brightness": "255"}' Jun 27 17:13:53 lignin python3[132815]: DEBUG:send_serial:sent b'PC: light 255\n' Jun 27 17:13:54 lignin python3[132815]: DEBUG:read_mqtt:received light msg: b'{"state": "OFF", "brightness": "255"}' Jun 27 17:13:54 lignin python3[132815]: DEBUG:send_serial:sent b'PC: light 0\n' Jun 27 17:14:48 lignin python3[132815]: WARNING:mqtt:Could not gracefully disconnect due to "Operation timed out". Forcing disconnection. Jun 27 17:14:48 lignin python3[132815]: ERROR:asyncio:Task exception was never retrieved Jun 27 17:14:48 lignin python3[132815]: future: Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/usr/lib/python3.9/asyncio/locks.py", line 226, in wait Jun 27 17:14:48 lignin python3[132815]: await fut Jun 27 17:14:48 lignin python3[132815]: asyncio.exceptions.CancelledError Jun 27 17:14:48 lignin python3[132815]: During handling of the above exception, another exception occurred: Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/usr/lib/python3.9/asyncio/tasks.py", line 492, in wait_for Jun 27 17:14:48 lignin python3[132815]: fut.result() Jun 27 17:14:48 lignin python3[132815]: asyncio.exceptions.CancelledError Jun 27 17:14:48 lignin python3[132815]: The above exception was the direct cause of the following exception: Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/venv/lib/python3.9/site-packages/asyncio_mqtt/client.py", line 337, i> Jun 27 17:14:48 lignin python3[132815]: return await asyncio.wait_for(fut, timeout=timeout, **kwargs) Jun 27 17:14:48 lignin python3[132815]: File "/usr/lib/python3.9/asyncio/tasks.py", line 494, in wait_for Jun 27 17:14:48 lignin python3[132815]: raise exceptions.TimeoutError() from exc Jun 27 17:14:48 lignin python3[132815]: asyncio.exceptions.TimeoutError Jun 27 17:14:48 lignin python3[132815]: During handling of the above exception, another exception occurred: Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/water_arduino.py", line 193, in read_until_failure Jun 27 17:14:48 lignin python3[132815]: await asyncio.gather(*tasks, return_exceptions=False) Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/venv/lib/python3.9/site-packages/asyncio_mqtt/client.py", line 337, i> Jun 27 17:14:48 lignin python3[132815]: return await asyncio.wait_for(fut, timeout=timeout, **kwargs) Jun 27 17:14:48 lignin python3[132815]: return await asyncio.wait_for(fut, timeout=timeout, **kwargs) Jun 27 17:14:48 lignin python3[132815]: File "/usr/lib/python3.9/asyncio/tasks.py", line 494, in wait_for Jun 27 17:14:48 lignin python3[132815]: raise exceptions.TimeoutError() from exc Jun 27 17:14:48 lignin python3[132815]: asyncio.exceptions.TimeoutError Jun 27 17:14:48 lignin python3[132815]: During handling of the above exception, another exception occurred: Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/water_arduino.py", line 193, in read_until_failure Jun 27 17:14:48 lignin python3[132815]: await asyncio.gather(*tasks, return_exceptions=False) Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/water_arduino.py", line 187, in write Jun 27 17:14:48 lignin python3[132815]: await client.publish(topic, data) Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/venv/lib/python3.9/site-packages/asyncio_mqtt/client.py", line 232, i> Jun 27 17:14:48 lignin python3[132815]: await self._wait_for(confirmation.wait(), timeout=timeout) Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/venv/lib/python3.9/site-packages/asyncio_mqtt/client.py", line 339, i> Jun 27 17:14:48 lignin python3[132815]: await self._wait_for(confirmation.wait(), timeout=timeout) Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/venv/lib/python3.9/site-packages/asyncio_mqtt/client.py", line 339, i> Jun 27 17:14:48 lignin python3[132815]: raise MqttError("Operation timed out") Jun 27 17:14:48 lignin python3[132815]: asyncio_mqtt.error.MqttError: Operation timed out Jun 27 17:14:48 lignin python3[132815]: During handling of the above exception, another exception occurred: Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/usr/lib/python3.9/asyncio/tasks.py", line 492, in wait_for Jun 27 17:14:48 lignin python3[132815]: fut.result() Jun 27 17:14:48 lignin python3[132815]: asyncio.exceptions.CancelledError Jun 27 17:14:48 lignin python3[132815]: The above exception was the direct cause of the following exception: Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/venv/lib/python3.9/site-packages/asyncio_mqtt/client.py", line 337, i> Jun 27 17:14:48 lignin python3[132815]: return await asyncio.wait_for(fut, timeout=timeout, **kwargs) Jun 27 17:14:48 lignin python3[132815]: File "/usr/lib/python3.9/asyncio/tasks.py", line 494, in wait_for Jun 27 17:14:48 lignin python3[132815]: raise exceptions.TimeoutError() from exc Jun 27 17:14:48 lignin python3[132815]: asyncio.exceptions.TimeoutError Jun 27 17:14:48 lignin python3[132815]: During handling of the above exception, another exception occurred: Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/venv/lib/python3.9/site-packages/asyncio_mqtt/client.py", line 529, i> Jun 27 17:14:48 lignin python3[132815]: await self.disconnect() Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/venv/lib/python3.9/site-packages/asyncio_mqtt/client.py", line 193, i> Jun 27 17:14:48 lignin python3[132815]: await self._wait_for(self._disconnected, timeout=timeout) Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/venv/lib/python3.9/site-packages/asyncio_mqtt/client.py", line 339, i> Jun 27 17:14:48 lignin python3[132815]: raise MqttError("Operation timed out") Jun 27 17:14:48 lignin python3[132815]: asyncio_mqtt.error.MqttError: Operation timed out Jun 27 17:14:48 lignin python3[132815]: During handling of the above exception, another exception occurred: Jun 27 17:14:48 lignin python3[132815]: Traceback (most recent call last): Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/water_arduino.py", line 202, in read_mqtt Jun 27 17:14:48 lignin python3[132815]: await read_until_failure() Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/water_arduino.py", line 193, in read_until_failure Jun 27 17:14:48 lignin python3[132815]: await asyncio.gather(*tasks, return_exceptions=False) Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/venv/lib/python3.9/site-packages/asyncio_mqtt/client.py", line 535, i> Jun 27 17:14:48 lignin python3[132815]: await self.force_disconnect() Jun 27 17:14:48 lignin python3[132815]: File "/home/username/git/water_guard/venv/lib/python3.9/site-packages/asyncio_mqtt/client.py", line 196, i> Jun 27 17:14:48 lignin python3[132815]: self._disconnected.set_result(None) Jun 27 17:14:48 lignin python3[132815]: asyncio.exceptions.InvalidStateError: invalid state