Repository navigation
Discard the late response of a cancelled request - #3076
sankalpsthakur wants to merge 1 commit into
Conversation
When execute() is cancelled while it waits, the response can still arrive after the next request is sent. RTU and ASCII responses carry no transaction id, so the next request returned it as its own. On cancel, keep a fresh response future, and let the next execute() wait for it before it sends, at most timeout_connect after the cancel. Socket framers are unchanged: handleFrame already skips a response with an old transaction id.
|
I just tried your test case, as expected it shows the problem, so with that I will try
I do suspect however that the problem might be older, because I can produce the problem without cancelling:
This is of course a configuration problem (timeout too small), but the effect seems identical to cancelling. I will keep you informed of my findings, because your method to solve might be the best one. |
|
Used your test case on v3.15.0 modified line 321: to adapt to the non passing of cancel exception. Your test FAILS, meaning this is as suspected a very old problem. Your fix raises a big problem, because it should be allowed to send a request to another device on the same line, without delay: Ex 1:
Ex 2:
If we get those 2 examples working, the only outstanding problem is if timeout is configured too low:
This seems theoretically insolvable, but it is a configuration problem. |
When an async
execute()is cancelled while it waits, the device can still answer after the next request is sent. With RTU/ASCII, which have no transaction id, and the same function code, the next request then returns that stale data, as in #3070. #3072 drops a late response only if it arrives before the next request or has another function code. On cancel,execute()now keeps a fresh response future, and the nextexecute()waits for it before sending, at mosttimeout_connectafter the cancel. Socket framers are unchanged (handleFramealready skips an old transaction id),CancelledErrorstill propagates as in #3010, and there is no API change.Validation
test_transaction_execute_cancel(new,FramerRTU): cancel a 4-register read, then read 5 registers. Withlate_response=Truethe 4-register reply arrives during the second call: ondev(c37dd72, with Partial solve ext. cancel sideeffects. #3072) it fails withassert [1, 2, 3, 4] == [1, 2, 3, 4, 5], and with this change it passes.late_response=False(the reply never comes) passes on both.pytest test/transaction: 47 passed on Python 3.10.18 and 3.14.7 (macOS), with 100% line and branch coverage ofpymodbus/transactionandtest/transaction(3.14).ruff check .,ruff format --check .,codespellandzuban checkon the touched files are clean, andpylintreports nothing new.execute()was already at the C901 limit of 10, so it gets# noqa: C901, likeconvert_from_registers.Fixes #3070
AI disclosure: written with an AI coding agent and tested as described above.