Place the persistent task in a task handler
This commit is contained in:
parent
e0eb490814
commit
37c9d65a9d
3 changed files with 72 additions and 69 deletions
|
|
@ -1,7 +1,5 @@
|
||||||
"""
|
"""
|
||||||
Module containing persistent features and the persistent differed
|
Module containing the task handler for Evennia deferred tasks, persistent or not.
|
||||||
tasks, generated by utils.delay(persistent=True).
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
@ -11,17 +9,20 @@ from evennia.server.models import ServerConfig
|
||||||
from evennia.utils.logger import log_trace, log_err
|
from evennia.utils.logger import log_trace, log_err
|
||||||
from evennia.utils.dbserialize import dbserialize, dbunserialize
|
from evennia.utils.dbserialize import dbserialize, dbunserialize
|
||||||
|
|
||||||
PERSISTENT_TASKS = None
|
TASK_HANDLER = None
|
||||||
|
|
||||||
class PersistentTasks(object):
|
class TaskHandler(object):
|
||||||
|
|
||||||
"""A light singleton wrapper allowing to access permanent tasks.
|
"""
|
||||||
|
A light singleton wrapper allowing to access permanent tasks.
|
||||||
|
|
||||||
|
When `utils.delay` is called, the task handler is used to create
|
||||||
|
the task. If `utils.delay` is called with `persistent=True`, the
|
||||||
|
task handler stores the new task and saves.
|
||||||
|
|
||||||
Permament tasks are created by `utils.delay` when the `persistent`
|
|
||||||
keyword argument is set to True. Tasks are saved in ServerConfig.
|
|
||||||
It's easier to access these tasks (should it be necessary) using
|
It's easier to access these tasks (should it be necessary) using
|
||||||
`evennia.utils.persistent.PERSISTSENT_TASKS`, which contains one
|
`evennia.scripts.taskhandler.TASK_HANDLER`, which contains one
|
||||||
instance of this class, and use its `add and `remove` methods.
|
instance of this class, and use its `add` and `remove` methods.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -88,56 +89,63 @@ class PersistentTasks(object):
|
||||||
any (any): any additional positional arguments to send to the callback
|
any (any): any additional positional arguments to send to the callback
|
||||||
|
|
||||||
Kwargs:
|
Kwargs:
|
||||||
|
persistent (bool, optional): persist the task (store it).
|
||||||
any (any): additional keyword arguments to send to the callback
|
any (any): additional keyword arguments to send to the callback
|
||||||
|
|
||||||
Note:
|
|
||||||
This doesn't create any delay at this time to call the task,
|
|
||||||
but the task is written in ServerConfig along with the
|
|
||||||
others.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
now = datetime.now()
|
persistent = kwargs.get("persistent", False)
|
||||||
delta = timedelta(seconds=timedelay)
|
if persistent:
|
||||||
|
del kwargs["persistent"]
|
||||||
|
now = datetime.now()
|
||||||
|
delta = timedelta(seconds=timedelay)
|
||||||
|
|
||||||
# Choose a free task_id
|
# Choose a free task_id
|
||||||
safe_args = []
|
safe_args = []
|
||||||
safe_kwargs = {}
|
safe_kwargs = {}
|
||||||
used_ids = self.tasks.keys()
|
used_ids = self.tasks.keys()
|
||||||
task_id = 1
|
task_id = 1
|
||||||
while task_id in used_ids:
|
while task_id in used_ids:
|
||||||
task_id += 1
|
task_id += 1
|
||||||
|
|
||||||
# Check that args and kwargs contain picklable information
|
# Check that args and kwargs contain picklable information
|
||||||
for arg in args:
|
for arg in args:
|
||||||
try:
|
try:
|
||||||
dbserialize(arg)
|
dbserialize(arg)
|
||||||
except (TypeError, AttributeError):
|
except (TypeError, AttributeError):
|
||||||
logger.log_err("The positional argument {} cannot be " \
|
logger.log_err("The positional argument {} cannot be " \
|
||||||
"pickled and will not be present in the arguments " \
|
"pickled and will not be present in the arguments " \
|
||||||
"fed to the callback {}".format(arg, callback))
|
"fed to the callback {}".format(arg, callback))
|
||||||
else:
|
else:
|
||||||
safe_args.append(arg)
|
safe_args.append(arg)
|
||||||
|
|
||||||
for key, value in kwargs.items():
|
for key, value in kwargs.items():
|
||||||
try:
|
try:
|
||||||
dbserialize(value)
|
dbserialize(value)
|
||||||
except (TypeError, AttributeError):
|
except (TypeError, AttributeError):
|
||||||
logger.log_err("The {} keyword argument {} cannot be " \
|
logger.log_err("The {} keyword argument {} cannot be " \
|
||||||
"pickled and will not be present in the arguments " \
|
"pickled and will not be present in the arguments " \
|
||||||
"fed to the callback {}".format(key, value, callback))
|
"fed to the callback {}".format(key, value, callback))
|
||||||
else:
|
else:
|
||||||
safe_kwargs[key] = value
|
safe_kwargs[key] = value
|
||||||
|
|
||||||
self.tasks[task_id] = (now + delta, callback, safe_args, safe_kwargs)
|
self.tasks[task_id] = (now + delta, callback, safe_args, safe_kwargs)
|
||||||
self.save()
|
self.save()
|
||||||
return task_id
|
callback = self.do_task
|
||||||
|
args = [task_id]
|
||||||
|
kwargs = {}
|
||||||
|
|
||||||
|
return task.deferLater(reactor, timedelay, callback, *args, **kwargs)
|
||||||
|
|
||||||
def remove(self, task_id):
|
def remove(self, task_id):
|
||||||
"""Remove a task without executing it.
|
"""Remove a persistent task without executing it.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
task_id (int): an existing task ID.
|
task_id (int): an existing task ID.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
A non-persistent task doesn't have a task_id, it is not stored
|
||||||
|
in the TaskHandler.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
del self.tasks[task_id]
|
del self.tasks[task_id]
|
||||||
if task_id in self.to_save:
|
if task_id in self.to_save:
|
||||||
|
|
@ -179,4 +187,5 @@ class PersistentTasks(object):
|
||||||
|
|
||||||
|
|
||||||
# Create the soft singleton
|
# Create the soft singleton
|
||||||
PERSISTENT_TASKS = PersistentTasks()
|
TASK_HANDLER = TaskHandler()
|
||||||
|
|
||||||
|
|
@ -455,10 +455,10 @@ class Evennia(object):
|
||||||
# (this also starts any that didn't yet start)
|
# (this also starts any that didn't yet start)
|
||||||
ScriptDB.objects.validate(init_mode=mode)
|
ScriptDB.objects.validate(init_mode=mode)
|
||||||
|
|
||||||
# start the persistent tasks
|
# start the task handler
|
||||||
from evennia.utils.persistent import PERSISTENT_TASKS
|
from evennia.scripts.taskhandler import TASK_HANDLER
|
||||||
PERSISTENT_TASKS.load()
|
TASK_HANDLER.load()
|
||||||
PERSISTENT_TASKS.create_delays()
|
TASK_HANDLER.create_delays()
|
||||||
|
|
||||||
# delete the temporary setting
|
# delete the temporary setting
|
||||||
ServerConfig.objects.conf("server_restart_mode", delete=True)
|
ServerConfig.objects.conf("server_restart_mode", delete=True)
|
||||||
|
|
|
||||||
|
|
@ -919,7 +919,7 @@ def uses_database(name="sqlite3"):
|
||||||
return engine == "django.db.backends.%s" % name
|
return engine == "django.db.backends.%s" % name
|
||||||
|
|
||||||
|
|
||||||
_PERSISTENT_TASKS = None
|
_TASK_HANDLER = None
|
||||||
|
|
||||||
def delay(timedelay, callback, *args, **kwargs):
|
def delay(timedelay, callback, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -931,9 +931,9 @@ def delay(timedelay, callback, *args, **kwargs):
|
||||||
arguments after `timedelay` seconds.
|
arguments after `timedelay` seconds.
|
||||||
args (any, optional): Will be used as arguments to callback
|
args (any, optional): Will be used as arguments to callback
|
||||||
Kwargs:
|
Kwargs:
|
||||||
persistent (bool, optional): should make the delay persistent
|
persistent (bool, optional): should make the delay persistent
|
||||||
over a reboot or reload
|
over a reboot or reload
|
||||||
any (any): Will be used to call the callback.
|
any (any): Will be used to call the callback.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
deferred (deferred): Will fire fire with callback after
|
deferred (deferred): Will fire fire with callback after
|
||||||
|
|
@ -943,6 +943,8 @@ def delay(timedelay, callback, *args, **kwargs):
|
||||||
specified here.
|
specified here.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
|
The task handler (`evennia.scripts.taskhandler.TASK_HANDLEr`) will
|
||||||
|
be called for persistent or non-persistent tasks.
|
||||||
If persistent is set to True, the callback, its arguments
|
If persistent is set to True, the callback, its arguments
|
||||||
and other keyword arguments will be saved in the database,
|
and other keyword arguments will be saved in the database,
|
||||||
assuming they can be. The callback will be executed even after
|
assuming they can be. The callback will be executed even after
|
||||||
|
|
@ -950,19 +952,11 @@ def delay(timedelay, callback, *args, **kwargs):
|
||||||
(and server down time).
|
(and server down time).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
global _PERSISTENT_TASKS
|
global _TASK_HANDLER
|
||||||
persistent = kwargs.get("persistent", False)
|
# Do some imports here to avoid circular import and speed things up
|
||||||
if persistent:
|
if _TASK_HANDLER is None:
|
||||||
del kwargs["persistent"]
|
from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER
|
||||||
# Do some imports here to avoid circular import and speed things up
|
return _TASK_HANDLER.add(timedelay, callback, *args, **kwargs)
|
||||||
if _PERSISTENT_TASKS is None:
|
|
||||||
from evennia.utils.persistent import PERSISTENT_TASKS as _PERSISTENT_TASKS
|
|
||||||
task_id = _PERSISTENT_TASKS.add(timedelay, callback, *args, **kwargs)
|
|
||||||
callback = _PERSISTENT_TASKS.do_task
|
|
||||||
args = [task_id]
|
|
||||||
kwargs = {}
|
|
||||||
|
|
||||||
return task.deferLater(reactor, timedelay, callback, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
_TYPECLASSMODELS = None
|
_TYPECLASSMODELS = None
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue