Made long running tasks cancellable. Added cancel button to cancellable tasks in the task list. Added APP_MODE env variable for determining if the app is running in development, test, or production.

This commit is contained in:
mmonkey
2021-09-29 02:40:12 -05:00
parent 26071d4e7a
commit 46205a1f83
20 changed files with 346 additions and 153 deletions
+25 -10
View File
@@ -48,23 +48,38 @@ class BackgroundScheduler:
return cls._instance
def _add(self, func, trigger, **trigger_args):
def schedule(self, func, trigger, **trigger_args):
if use_APScheduler:
return self.scheduler.add_job(func=func, trigger=trigger, **trigger_args)
# Expects a lambda expression for the task, so that the task isn't instantiated before the task is scheduled
def schedule_task(self, user, task, trigger, **trigger_args):
# Expects a lambda expression for the task
def schedule_task(self, task, user=None, trigger='cron', **trigger_args):
if use_APScheduler:
def scheduled_task():
worker_task = task()
worker_task.scheduled = True
WorkerThread.add(user, worker_task)
return self.schedule(func=scheduled_task, trigger=trigger, **trigger_args)
return self._add(func=scheduled_task, trigger=trigger, **trigger_args)
# Expects a lambda expression for the task, so that the task isn't instantiated before the task is scheduled
def schedule_task_immediately(self, user, task):
# Expects a list of lambda expressions for the tasks
def schedule_tasks(self, tasks, user=None, trigger='cron', **trigger_args):
if use_APScheduler:
def scheduled_task():
WorkerThread.add(user, task())
for task in tasks:
self.schedule_task(task, user=user, trigger=trigger, **trigger_args)
return self._add(func=scheduled_task, trigger='date')
# Expects a lambda expression for the task
def schedule_task_immediately(self, task, user=None):
if use_APScheduler:
def immediate_task():
WorkerThread.add(user, task())
return self.schedule(func=immediate_task, trigger='date')
# Expects a list of lambda expressions for the tasks
def schedule_tasks_immediately(self, tasks, user=None):
if use_APScheduler:
for task in tasks:
self.schedule_task_immediately(task, user)
# Remove all jobs
def remove_all_jobs(self):
self.scheduler.remove_all_jobs()
+29 -6
View File
@@ -21,6 +21,8 @@ STAT_WAITING = 0
STAT_FAIL = 1
STAT_STARTED = 2
STAT_FINISH_SUCCESS = 3
STAT_ENDED = 4
STAT_CANCELLED = 5
# Only retain this many tasks in dequeued list
TASK_CLEANUP_TRIGGER = 20
@@ -50,7 +52,7 @@ class WorkerThread(threading.Thread):
_instance = None
@classmethod
def getInstance(cls):
def get_instance(cls):
if cls._instance is None:
cls._instance = WorkerThread()
return cls._instance
@@ -67,12 +69,13 @@ class WorkerThread(threading.Thread):
@classmethod
def add(cls, user, task):
ins = cls.getInstance()
ins = cls.get_instance()
ins.num += 1
log.debug("Add Task for user: {}: {}".format(user, task))
username = user if user is not None else 'System'
log.debug("Add Task for user: {}: {}".format(username, task))
ins.queue.put(QueuedTask(
num=ins.num,
user=user,
user=username,
added=datetime.now(),
task=task,
))
@@ -134,6 +137,12 @@ class WorkerThread(threading.Thread):
self.queue.task_done()
def end_task(self, task_id):
ins = self.get_instance()
for __, __, __, task in ins.tasks:
if str(task.id) == str(task_id) and task.is_cancellable:
task.stat = STAT_CANCELLED if task.stat == STAT_WAITING else STAT_ENDED
class CalibreTask:
__metaclass__ = abc.ABCMeta
@@ -147,10 +156,11 @@ class CalibreTask:
self.message = message
self.id = uuid.uuid4()
self.self_cleanup = False
self._scheduled = False
@abc.abstractmethod
def run(self, worker_thread):
"""Provides the caller some human-readable name for this class"""
"""The main entry-point for this task"""
raise NotImplementedError
@abc.abstractmethod
@@ -158,6 +168,11 @@ class CalibreTask:
"""Provides the caller some human-readable name for this class"""
raise NotImplementedError
@abc.abstractmethod
def is_cancellable(self):
"""Does this task gracefully handle being cancelled (STAT_ENDED, STAT_CANCELLED)?"""
raise NotImplementedError
def start(self, *args):
self.start_time = datetime.now()
self.stat = STAT_STARTED
@@ -208,7 +223,7 @@ class CalibreTask:
We have a separate dictating this because there may be certain tasks that want to override this
"""
# By default, we're good to clean a task if it's "Done"
return self.stat in (STAT_FINISH_SUCCESS, STAT_FAIL)
return self.stat in (STAT_FINISH_SUCCESS, STAT_FAIL, STAT_ENDED, STAT_CANCELLED)
'''@progress.setter
def progress(self, x):
@@ -226,6 +241,14 @@ class CalibreTask:
def self_cleanup(self, is_self_cleanup):
self._self_cleanup = is_self_cleanup
@property
def scheduled(self):
return self._scheduled
@scheduled.setter
def scheduled(self, is_scheduled):
self._scheduled = is_scheduled
def _handleError(self, error_message):
self.stat = STAT_FAIL
self.progress = 1