-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: issue212 #216
fix: issue212 #216
Conversation
Codecov Report
@@ Coverage Diff @@
## main #216 +/- ##
=======================================
+ Coverage 89.7% 91.7% +2.0%
=======================================
Files 6 6
Lines 738 836 +98
Branches 156 177 +21
=======================================
+ Hits 662 767 +105
+ Misses 49 46 -3
+ Partials 27 23 -4
|
Thanks for opening this PR. 👍 Let me have a look. :) I assume the overall purpose is to make
That's the purpose of this PR, right? Let me know if I'm wrong. If I'm right, then this PR also relates to #48. I'll provide more feedback after we settle on the intent of this PR. I hope that makes sense. :) |
Yes, after adding the judgment, it will become a reusable context. I read #48, and I don’t know much about the publish and QOS in the question. What I can only confirm is that this PR will make aiomqtt a reusable of the context. |
To be honest, I don't really like to use context in projects, such as the example used in fastapi in your documentation. client = aiomqtt.Client("test.mosquitto.org")
@contextlib.asynccontextmanager
async def lifespan(app):
await clinet.connect()
yield
await client.disconnect() I found that you mentioned paho.client.reconnect in #48. |
Great, because that's what we need to test for then! :) What I need from you to merge this PR:
The test part is the most important. I can do the docs if you don't feel like it. :) On the topic of "automatic reconnect": Yes! That would be great to have. It is also quite difficult to get right. 😅 See #6 and #26 for some of the subtleties. |
OK, I'll do it. |
This PR changed 6 points:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great and thanks for the detailed tests! 👍 :) The more coverage we get on that front the better.
Have a look at the comments in the review. Let me know if anything is unclear.
Side note for future reference (not directly relevant to this PR)
Looking through the internals like this again makes me wish that I never exposed connect
and disconnect
as part of the public interface. 😅 It's quite the maintenance burden!
Also, now we have this mess of internal state (I'm the cause of that myself):
self._connected: asyncio.Future
self._disconnected: asyncio.Future
self._lock: asyncio.Lock
All three variables have semantic overlap! Really, we should just have the single _lock
(where "lock acquired" means "client connecting/connected"). Extending on that: Have all internal state inside a tagged union (sum type) in rust-style, concurrency-safe semantics.
In any case, all of that is just food for thought for, e.g., an anyio-based rewrite. :)
Hi vvanglro, this is a very cool addition, thank you! 🎉
Our documentation didn't document It'd be a breaking change nonetheless, but I think it's valid to remove it as well. I'm always for simplifying things 😄 |
Should we deprecate first before removing? |
Good to know that I'm not the only one. :)
Yes! I'd also like to point out that our users may still manually call "connect/disconnect": They simply call "__aenter__/__aexit__". :)) Hopefully, these oddly-named functions discourage that pattern. In any case, we can document that as a "compatibility workaround for existing code that relies on manual 'connect/disconnect' calls". |
Thank you again for your great work on this PR, @vvanglro. 👍 I plan to do the code review this weekend. I'm really tied up until then. :) |
I'm thinking about some problems,🤯 if we remove connect/disconnect, based main code and the current PR, there will be the following three situations. The first situation(Base main code, This will establish 10 connections simultaneously): from asyncio_mqtt import Client
async def run1(message):
async with Client("192.168.5.24", username="admin", password="123456") as client:
await client.publish("humidity/outside", payload=message)
# Maybe it can only be concurrently in context.
# tasks = [asyncio.create_task(client.publish("humidity/outside", payload=i)) for i in range(10)]
# await asyncio.gather(*tasks)
async def gather_task1():
tasks = [asyncio.create_task(run1(i)) for i in range(10)]
await asyncio.gather(*tasks)
if __name__ == '__main__':
import asyncio
asyncio.get_event_loop().run_until_complete(gather_task1()) The two situation(Base current PR, Not reentrant will result in an error): from asyncio_mqtt import Client
client = Client("192.168.5.24", username="admin", password="123456")
async def run2(message):
async with client:
await client.publish("humidity/outside", payload=message)
# Maybe it can only be concurrently in context.
# tasks = [asyncio.create_task(client.publish("humidity/outside", payload=i)) for i in range(10)]
# await asyncio.gather(*tasks)
async def gather_task2():
tasks = [asyncio.create_task(run2(i)) for i in range(10)]
await asyncio.gather(*tasks)
if __name__ == '__main__':
import asyncio
asyncio.get_event_loop().run_until_complete(gather_task2()) The three situation(There is only 1 connection, and no error will be generated): from asyncio_mqtt import Client
client = Client("192.168.5.24", username="admin", password="123456")
async def run3(message):
await client.publish("humidity/outside", payload=message)
async def gather_task3():
await client.connect()
tasks = [asyncio.create_task(run3(i)) for i in range(10)]
await asyncio.gather(*tasks)
await client.disconnect()
if __name__ == '__main__':
import asyncio
asyncio.get_event_loop().run_until_complete(gather_task3()) So is it possible to consider from other angles and then keep connect/disconnect. |
First of all, I apologize about the long delay. In any case, this PR now looks good to me. 👍 Though I can't merge it in because GitHub says "This branch cannot be rebased due to conflicts". I guess that the main branch updated (probably a bot-based commit) in the meantime. @vvanglro Can I get you to rebase this PR on top of the master branch? Thanks! Then I'll merge it in right away. :) |
It was just a simple merge conflict. I added a merge commit on it to fix it. :) Thank you for a great contribution to asyncio-mqtt. 👍 |
This is on the main branch now? Do I still need to call disconnect? |
Yes, and part of the v1.0.0 release. :)
We did not remove |
This PR fixes #212 .
If
_disconnected
is found to be completed after connecting, it is not correct, so we need to reset it.If
_connected
is still in the completed state after disconnection, reset it.