Skip to content

fix(async): synchronize connect() promise with connection_made callback - #3021

Open
Yuvrajup wants to merge 5 commits into
pymodbus-dev:devfrom
Yuvrajup:fix/async-tcp-client-state-3019
Open

fix(async): synchronize connect() promise with connection_made callback#3021
Yuvrajup wants to merge 5 commits into
pymodbus-dev:devfrom
Yuvrajup:fix/async-tcp-client-state-3019

Conversation

@Yuvrajup

@Yuvrajup Yuvrajup commented Sep 9, 2026

Copy link
Copy Markdown

Closes #3019

@janiversen janiversen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is overly complicated and not needed, current solution uses the standard asyncio methods.

client,connect returns the value comming from asyncio, which according to the documentation is true/false depending on whether a connection was established.

client.connected tests if the connection is stil open by referring to the transport object. Remark connection_made/ connection_lost changes the transport object.

The issue you refer to, is not actually an issue in pymodbus (see the discussion) but a device problem.

@janiversen janiversen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want this merged, you need to make a test case that shows that the current solution is wrong and yours work.

@Yuvrajup

Copy link
Copy Markdown
Author

Challenge accepted, @janiversen! I completely understand wanting to keep the library lean and relying on standard asyncio methods.

You are right that create_connection returns the underlying connection. However, the issue is that there is a microscopic event-loop gap between create_connection resolving and the protocol's connection_made() callback actually firing to set the .transport object inside the client.

I just pushed a new test case (test_async_connect_race_condition) that artificially delays the connection_made callback by a few milliseconds to deterministically simulate a slow event loop or hardware latency.

  • Without this PR's synchronization, client.connect() returns True, but client.connected evaluates to False (crashing subsequent requests).
  • With this PR, client.connect() safely awaits the callback, ensuring the transport is fully hydrated before returning control to the caller.

Let me know what you think of the test case!

@janiversen

janiversen commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Forget about that race, pymodbus do not have the transport object until connection_made is called.

Apart from that in my experience, when debugging, connection_made was always called before the connect returned.

Just checked your test case, the delay is inside connection_made() and thus in pymodbus code, so your test case does not show if connection_made is called before connect returns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AsyncModbusTcpClient.connect() returns True while .connected property is False (3.13.1)

2 participants