[tor-commits] [stem/master] Expand event listener tutorial

atagar at torproject.org atagar at torproject.org
Thu Nov 28 00:45:50 UTC 2019


commit 9b8d76926083f66f090893c49e8c9714f81147a1
Author: Damian Johnson <atagar at 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



More information about the tor-commits mailing list