commit 9b8d76926083f66f090893c49e8c9714f81147a1 Author: Damian Johnson atagar@torproject.org Date: Wed Nov 27 16:39:14 2019 -0800
Expand event listener tutorial
George had a great question today about catching event listener exceptions...
https://lists.torproject.org/pipermail/tor-dev/2019-November/014092.html
Expanding our event listener tutorial to dive a bit deeper into this topic. --- docs/_static/example/broken_listener.py | 15 +++++++++++ docs/_static/example/queue_listener.py | 17 +++++++++++++ docs/_static/example/slow_listener.py | 16 ++++++++++++ docs/tutorials/tortoise_and_the_hare.rst | 43 ++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+)
diff --git a/docs/_static/example/broken_listener.py b/docs/_static/example/broken_listener.py new file mode 100644 index 00000000..7ad0c2b8 --- /dev/null +++ b/docs/_static/example/broken_listener.py @@ -0,0 +1,15 @@ +import time + +from stem.control import EventType, Controller + + +def broken_handler(event): + print('start of broken_handler') + raise ValueError('boom') + print('end of broken_handler') + + +with Controller.from_port() as controller: + controller.authenticate() + controller.add_event_listener(broken_handler, EventType.BW) + time.sleep(2) diff --git a/docs/_static/example/queue_listener.py b/docs/_static/example/queue_listener.py new file mode 100644 index 00000000..55b0f13f --- /dev/null +++ b/docs/_static/example/queue_listener.py @@ -0,0 +1,17 @@ +import queue +import time + +from stem.control import EventType, Controller + + +with Controller.from_port() as controller: + controller.authenticate() + + start_time = time.time() + event_queue = queue.Queue() + + controller.add_event_listener(lambda event: event_queue.put(event), EventType.BW) + + while time.time() - start_time < 2: + event = event_queue.get() + print('I got a BW event for %i bytes downloaded and %i bytes uploaded' % (event.read, event.written)) diff --git a/docs/_static/example/slow_listener.py b/docs/_static/example/slow_listener.py new file mode 100644 index 00000000..a557ae87 --- /dev/null +++ b/docs/_static/example/slow_listener.py @@ -0,0 +1,16 @@ +import time + +from stem.control import EventType, Controller + + +with Controller.from_port() as controller: + def slow_handler(event): + age = time.time() - event.arrived_at + unprocessed_count = controller._event_queue.qsize() + + print("processing a BW event that's %0.1f seconds old (%i more events are waiting)" % (age, unprocessed_count)) + time.sleep(5) + + controller.authenticate() + controller.add_event_listener(slow_handler, EventType.BW) + time.sleep(10) diff --git a/docs/tutorials/tortoise_and_the_hare.rst b/docs/tutorials/tortoise_and_the_hare.rst index 2b067f98..8d4f6268 100644 --- a/docs/tutorials/tortoise_and_the_hare.rst +++ b/docs/tutorials/tortoise_and_the_hare.rst @@ -32,3 +32,46 @@ uploaded. :emphasize-lines: 53-55,62-67 :language: python
+Advanced Listeners +------------------ + +When you attach a listener to a :class:`~stem.control.Controller` events are +processed within a dedicated thread. This is convenient for simple uses, but +can make troubleshooting your code confusing. For example, exceptions have +nowhere to propagate... + +.. literalinclude:: /_static/example/broken_listener.py + :language: python + +:: + + % python demo.py + start of broken_handler + start of broken_handler + start of broken_handler + +... and processing events slower than they're received will make your listener +fall behind. This can result in a memory leak for long running processes... + +.. literalinclude:: /_static/example/slow_listener.py + :language: python + +:: + + % python demo.py + processing a BW event that's 0.9 seconds old (0 more events are waiting) + processing a BW event that's 4.9 seconds old (3 more events are waiting) + processing a BW event that's 8.9 seconds old (7 more events are waiting) + +Avoid performing heavy business logic directly within listeners. For example, a +producer/consumer pattern sidesteps these issues... + +.. literalinclude:: /_static/example/queue_listener.py + :language: python + +:: + + % python demo.py + I got a BW event for 20634 bytes downloaded and 2686 bytes uploaded + I got a BW event for 0 bytes downloaded and 0 bytes uploaded + I got a BW event for 0 bytes downloaded and 0 bytes uploaded
tor-commits@lists.torproject.org