From c7bf7736055c0ae174823d1d2a21fa7a253940d7 Mon Sep 17 00:00:00 2001 From: davewiththenicehat <54369722+davewiththenicehat@users.noreply.github.com> Date: Fri, 16 Apr 2021 10:55:24 -0400 Subject: [PATCH] taskhandler suppress cancel error Added an errback to handle errors within task handler's deferred instance. Without this instances of deferred cause a traceback when a deferred is canceled without errback or callback having been called. This traceback does not end execution, and ultimately would only show to main console. Reference cancel: https://github.com/twisted/twisted/blob/trunk/src/twisted/internet/defer.py All evennia unit tests pass. --- evennia/scripts/taskhandler.py | 16 +++++++++++++++- evennia/utils/tests/test_utils.py | 8 +++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/evennia/scripts/taskhandler.py b/evennia/scripts/taskhandler.py index 11ac144a94..3273e27e8a 100644 --- a/evennia/scripts/taskhandler.py +++ b/evennia/scripts/taskhandler.py @@ -6,6 +6,7 @@ from datetime import datetime, timedelta from twisted.internet import reactor from twisted.internet.task import deferLater +from twisted.internet.defer import CancelledError as DefCancelledError from evennia.server.models import ServerConfig from evennia.utils.logger import log_err from evennia.utils.dbserialize import dbserialize, dbunserialize @@ -13,6 +14,17 @@ from evennia.utils.dbserialize import dbserialize, dbunserialize TASK_HANDLER = None +def handle_error(*args, **kwargs): + """ + Handle errors withing deferred objects. + """ + for arg in args: + # suppress cancel errors + if arg.type == DefCancelledError: + continue + raise arg + + class TaskHandler(object): """ @@ -179,7 +191,9 @@ class TaskHandler(object): deferLater(self.clock, timedelay, callback, *args, **kwargs) return task_id - return deferLater(self.clock, timedelay, callback, *args, **kwargs) + d = deferLater(self.clock, timedelay, callback, *args, **kwargs) + d.addErrback(handle_error) + return d def remove(self, task_id): """Remove a persistent task without executing it. diff --git a/evennia/utils/tests/test_utils.py b/evennia/utils/tests/test_utils.py index ea23601fce..bebea149ce 100644 --- a/evennia/utils/tests/test_utils.py +++ b/evennia/utils/tests/test_utils.py @@ -10,7 +10,7 @@ import mock from django.test import TestCase from datetime import datetime -from twisted.internet import task, reactor +from twisted.internet import task from evennia.utils.ansi import ANSIString from evennia.utils import utils @@ -338,3 +338,9 @@ class TestDelay(EvenniaTest): _TASK_HANDLER.clock.advance(1) # make time pass self.assertEqual(self.char1.ndb.dummy_var, 'dummy_func ran') self.char1.ndb.dummy_var = False + # test canceling a deferral. + deferal_inst = utils.delay(1, dummy_func, self.char1.dbref) + deferal_inst.cancel() + _TASK_HANDLER.clock.advance(1) # make time pass + self.assertEqual(self.char1.ndb.dummy_var, False) + self.char1.ndb.dummy_var = False