Instead of NullContext, you might try structuring things so that the
scheduler is in a separate StackContext "layer" than the worker
function (like ioloop.PeriodicCallback). Note that PeriodicCallback
will mostly work fine as-is with async functions, but for overrun
protection you need something that knows its function is asynchronous.
class PeriodicAsyncCallback(PeriodicCallback):
def _run(self):
if not self._running:
return
with ExceptionStackContext(functools.partial(self.handle_exc,
self.counter)):
self.callback(callback=functools.partial(self.handle_finished,
self.counter))
def handle_exc(self, counter, typ, value, tb):
logging.error("error in PeriodicAsyncCallback", exc_info=(typ,value,tb))
if self.counter == counter:
self._schedule_next()
def handle_finished(self, counter):
if self.counter == counter:
self._schedule_next()
def _schedule_next(self)
# counter ensures that even if a callback generates multiple
exceptions in its
# stack context we won't get multiple copies rescheduled.
self.counter += 1
super(PeriodicCallback, self)._schedule_next()