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

self cancelling watcher #110

Closed
mckenziec opened this issue Sep 9, 2019 · 8 comments
Closed

self cancelling watcher #110

mckenziec opened this issue Sep 9, 2019 · 8 comments

Comments

@mckenziec
Copy link

  • etcd3-py version: latest
  • Python version: 2.7.5
  • Operating System: CENTOS 7.5

Description

Maybe this is a Python thing I can work out, but I'm trying to have a watcher that'll self cancel within an event callback. Like watch once, or watch until some condition is satisfied, then cancel itself.

I've designed a kind of request/approval protocol on top of etcd and I'd like the watch to end when my approval watch fires. Any suggestions?

Excellent, stable library BTW. Thanks!

What I Did

            def watch_apr(ev):
                k = ev.key
                v = ev.value
                # cancel here somehow

            apr_watcher.onEvent(EventType.PUT, watch_apr)
            apr_watcher.runDaemon()
            while apr_watcher <> None:
                time.sleep(1)
@issue-label-bot
Copy link

Issue Label Bot is not confident enough to auto-label this issue. See dashboard for more details.

@Revolution1
Copy link
Owner

@mckenziec
Copy link
Author

I knew that! Thanks Revolution1.

@mckenziec mckenziec reopened this Sep 10, 2019
@mckenziec
Copy link
Author

Actually I played with watch_once() and it blocks the main thread (fine) but doesn't release after the callback executes. Maybe I'm using it wrong:

            apr_watcher = cli.Watcher(key=apath, progress_notify=True, prev_kv=False, prefix=True)

            def watch_apr(ev):
                if ev.type == EventType.PUT:
                    k = ev.key
                    v = ev.value
                    # do stuff...
                    print "watch complete!"
            print "watching once..."
            apr_watcher.watch_once(watch_apr)
            print "watching twice?"

During execution I'll see:

watching once...
watch complete!

And it won't continue. Any suggestions? Thanks.

@mckenziec
Copy link
Author

Ah got it. I have to return the event in my once run callback:

            apr_watcher = cli.Watcher(key=apath, progress_notify=True, prev_kv=False, prefix=True)

            def watch_apr(ev):
                if ev.type == EventType.PUT:
                    k = ev.key
                    v = ev.value
                    # do stuff...
                    print "watch complete!"
                    return ev

            print "watching once..."
            apr_watcher.watch_once(watch_apr)
            print "watching twice?"

@Revolution1
Copy link
Owner

uh... no
watch_once accepts a filter, not callback
A filter only tells the dispatcher whether to keep this event or just drop it.
A filter can be either a EventType, a Regex pattern string or a function that returns True if event match what you need.

So you are using the filter as a callback.
If you don't return a True value, the dispather treats the event as a uneeded one, and keep on waiting for another valid event.

the correct way to use is:

w = Watcher(...)
e = w.watch_once() # default None accept all kinds of event
# or
e = w.watch_once('.*123') # regex filter the event of which key ends with '123'

The you can use the returned Event e

@mckenziec
Copy link
Author

Ok, that makes sense. I was confused by the onEvent() taking a filter_or_cb and also cb, and that the constructor for Watcher includes the key'ing, but of course I can further filter for something like EventType. Great, I can remove the callback, which was a pain to debug as it runs in another thread. Anyways, thanks for the follow up!

@Revolution1
Copy link
Owner

The purpose of filter_or_cb is:

In these use case:

  1. watch only one key or prefix
w = Watcher(key="key or prefix you want to watch")
w.onEvent(lambda event: do sth...) # the first arg is a callback
  1. watch only one multiple key or prefix
w = Watcher(key="wider key or prefix that covers your need")
w.onEvent("filter of key or prefix 1", lambda event: do sth...) # the first arg is a filter
w.onEvent("filter of key or prefix 2", lambda event: do sth...) # the first arg is a filter

thus, only one watcher is created, only one stream open

In conclusion, the first argument or onEvent can be either a filter or callback, so it's named filter_or_cb

@Revolution1 Revolution1 pinned this issue Sep 12, 2019
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

No branches or pull requests

2 participants