Skip to content
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

Python recv on queryable can't be used to reply #459

Closed
gar1t opened this issue Feb 27, 2025 · 4 comments · Fixed by #461
Closed

Python recv on queryable can't be used to reply #459

gar1t opened this issue Feb 27, 2025 · 4 comments · Fixed by #461
Assignees
Labels
bug Something isn't working

Comments

@gar1t
Copy link

gar1t commented Feb 27, 2025

Describe the bug

The queryable example uses a callback + blocking loop to handle messages. This works file but is an odd interface for a listener, requiring an arbitrary sleep state that can otherwise be replaced by a blocking recv:

listen = session.declare_queryable("**")
while True:
    query = listen.recv()
    query.reply(query.key_expr, "Hi")

This is far more ergonomic interface IMO, however, the query.reply never makes it to the caller. The get call from any client times out. All of the examples use the callback form so I don't have a working example to go by.

Am I missing something in the setup/use of the listen.recv() interface?

To reproduce

  1. Create a process that uses the non-callback variant of declare_queryable (see above)
  2. Create a process that gets a matching key
  3. Subscriber gets the messages and calls query.reply but the caller does not receive the reply - it times out

System info

  • Platform: x86_64 x86_64 x86_64 GNU/Linux
  • eclipse-zenoh: 1.2.1
@gar1t gar1t added the bug Something isn't working label Feb 27, 2025
@wyfo
Copy link
Contributor

wyfo commented Feb 27, 2025

I can reproduce the bug. The strange thing is that if I do another query, on a parallel process, the response to the second query goes to the first one. I'm investigating more.

EDIT: actually, the query times out, but the response arrives just after the timeout.

@wyfo
Copy link
Contributor

wyfo commented Feb 27, 2025

Ok, we have found the explanation: a query can have many replies, and ends with a response-final message, which is automatically sent when the query object is finalized. It works well in languages like Rust or C++, but Python scoping rules are completely different, and the query object is kept alive after the loop iteration. It is only finalized when query is reassigned, for example if another query is received, the variable is overwritten, and the response-final message is sent, which explains the strange behavior that I observed.
The solution would be to add a context manager to the query object, so you would have to write:

listen = session.declare_queryable("**")
while True:
    with listen.recv() as query:
        query.reply(query.key_expr, "Hi")

I will open a PR to add the context manager.

P.S. This workaround also works, but a context manager is better

listen = session.declare_queryable("**")
while True:
    query = listen.recv()
    query.reply(query.key_expr, "Hi")
    query = None  # force the previous value to be finalized

@wyfo
Copy link
Contributor

wyfo commented Feb 28, 2025

#461 adds context manager to query, and updates z_queryable example to use channel form with the new context manager.

@wyfo wyfo self-assigned this Feb 28, 2025
@gar1t
Copy link
Author

gar1t commented Feb 28, 2025

I can confirm this PR fixes the issue!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants