[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Expand event listener tutorial
commit 9b8d76926083f66f090893c49e8c9714f81147a1
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
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 mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits