Permalink
Browse files

add call_in_loop, which calls a function in a loop

it does some error reporting and ensures that the only way to exit the
loop is to raise GreenletExit.
  • Loading branch information...
1 parent 391f7c3 commit bf5e0352ca3edb31e32b7eb632659ded061c1f96 @schmir schmir committed Oct 18, 2011
Showing with 78 additions and 0 deletions.
  1. +2 −0 MANIFEST.in
  2. +43 −0 qs/misc.py
  3. +33 −0 tests/test_call_in_loop.py
View
@@ -3,13 +3,15 @@ include README.rst
include conftest.py
include qs/__init__.py
include qs/jobs.py
+include qs/misc.py
include qs/proc.py
include qs/qserve.py
include qs/rpcclient.py
include qs/rpcserver.py
include qs/slave.py
include setup.cfg
include setup.py
+include tests/test_call_in_loop.py
include tests/test_jobs.py
include tests/test_proc.py
include tests/test_qserve.py
View
@@ -0,0 +1,43 @@
+
+import sys
+import gevent
+import traceback
+
+def safecall(fun, *args, **kwargs):
+ try:
+ return fun(*args, **kwargs)
+ except gevent.GreenletExit:
+ raise
+ except:
+ pass
+
+class call_in_loop(object):
+ def __init__(self, sleep_time, function, *args, **kwargs):
+ self.sleep_time = sleep_time
+ self.function = function
+ self.args = args
+ self.kwargs = kwargs
+
+ def iterate(self):
+ try:
+ self.function(*self.args, **self.kwargs)
+ except gevent.GreenletExit:
+ raise
+ except:
+ safecall(self.report_error)
+ safecall(gevent.sleep, self.sleep_time)
+
+ def __call__(self):
+ while 1:
+ try:
+ self.iterate()
+ except gevent.GreenletExit:
+ raise
+ except:
+ pass
+
+ def report_error(self):
+ exc_info = sys.exc_info()
+ sys.stderr.write("\nError while calling %s:\n" % self.function)
+ traceback.print_exception(*exc_info)
+ sys.stderr.write("\n")
View
@@ -0,0 +1,33 @@
+#! /usr/bin/env py.test
+
+import pytest
+import time
+import gevent
+from qs.misc import call_in_loop
+
+
+def throw_error():
+ raise RuntimeError("as requested")
+
+
+def test_iterate_error():
+ c = call_in_loop(0.05, throw_error)
+ stime = time.time()
+ c.iterate()
+ needed = time.time() - stime
+ assert needed > 0.05
+
+
+def test_fail_and_restart():
+ lst = []
+
+ def doit():
+ lst.append(len(lst))
+ print "doit", lst
+ if len(lst) == 5:
+ raise RuntimeError("size is 5")
+ elif len(lst) == 10:
+ raise gevent.GreenletExit("done")
+
+ c = call_in_loop(0.001, doit)
+ pytest.raises(gevent.GreenletExit, c)

0 comments on commit bf5e035

Please sign in to comment.