diff --git a/queue_job/job.py b/queue_job/job.py
index c121e16eef..2045bf8362 100644
--- a/queue_job/job.py
+++ b/queue_job/job.py
@@ -19,6 +19,7 @@
PENDING = 'pending'
ENQUEUED = 'enqueued'
+CANCELLED = 'cancelled'
DONE = 'done'
STARTED = 'started'
FAILED = 'failed'
@@ -27,6 +28,7 @@
(ENQUEUED, 'Enqueued'),
(STARTED, 'Started'),
(DONE, 'Done'),
+ (CANCELLED, 'Cancelled'),
(FAILED, 'Failed')]
DEFAULT_PRIORITY = 10 # used by the PriorityQueue to sort the jobs
@@ -283,6 +285,9 @@ def _load_from_db_record(cls, job_db_record):
if stored.date_done:
job_.date_done = stored.date_done
+ if stored.date_cancelled:
+ job_.date_cancelled = stored.date_cancelled
+
job_.state = stored.state
job_.result = stored.result if stored.result else None
job_.exc_info = stored.exc_info if stored.exc_info else None
@@ -435,6 +440,7 @@ def __init__(self, func,
self.date_enqueued = None
self.date_started = None
self.date_done = None
+ self.date_cancelled = None
self.result = None
self.exc_name = None
@@ -514,6 +520,7 @@ def _store_values(self, create=False):
'date_started': False,
'date_done': False,
'exec_time': False,
+ 'date_cancelled': False,
'eta': False,
'identity_key': False,
"worker_pid": self.worker_pid,
@@ -527,6 +534,8 @@ def _store_values(self, create=False):
vals['date_done'] = self.date_done
if self.exec_time:
vals["exec_time"] = self.exec_time
+ if self.date_cancelled:
+ vals['date_cancelled'] = self.date_cancelled
if self.eta:
vals['eta'] = self.eta
if self.identity_key:
@@ -671,6 +680,7 @@ def set_pending(self, result=None, reset_retry=True):
self.date_done = None
self.worker_pid = None
self.date_done = None
+ self.date_cancelled = None
if reset_retry:
self.retry = 0
if result is not None:
@@ -695,6 +705,12 @@ def set_done(self, result=None):
if result is not None:
self.result = result
+ def set_cancelled(self, result=None):
+ self.state = CANCELLED
+ self.date_cancelled = datetime.now()
+ if result is not None:
+ self.result = result
+
def set_failed(self, **kw):
self.state = FAILED
for k, v in kw.items():
diff --git a/queue_job/models/queue_job.py b/queue_job/models/queue_job.py
index d58744f387..3986688aa3 100644
--- a/queue_job/models/queue_job.py
+++ b/queue_job/models/queue_job.py
@@ -11,7 +11,7 @@
from odoo.osv import expression
from ..fields import JobSerialized
-from ..job import DONE, PENDING, STATES, Job
+from ..job import CANCELLED, DONE, PENDING, STATES, Job
_logger = logging.getLogger(__name__)
@@ -91,6 +91,7 @@ class QueueJob(models.Model):
group_operator="avg",
help="Time required to execute this job in seconds. Average when grouped.",
)
+ date_cancelled = fields.Datetime(readonly=True)
eta = fields.Datetime(string='Execute only after')
retry = fields.Integer(string='Current try')
@@ -200,6 +201,8 @@ def _change_job_state(self, state, result=None):
job_.set_done(result=result)
elif state == PENDING:
job_.set_pending(result=result)
+ elif state == CANCELLED:
+ job_.set_cancelled(result=result)
else:
raise ValueError('State not supported: %s' % state)
job_.store()
@@ -210,6 +213,12 @@ def button_done(self):
self._change_job_state(DONE, result=result)
return True
+ @api.multi
+ def button_cancelled(self):
+ result = _('Cancelled by %s') % self.env.user.name
+ self._change_job_state(CANCELLED, result=result)
+ return True
+
@api.multi
def requeue(self):
self._change_job_state(PENDING)
@@ -271,7 +280,9 @@ def autovacuum(self):
deadline = datetime.now() - timedelta(
days=int(channel.removal_interval))
jobs = self.search(
- [('date_done', '<=', deadline),
+ ['|',
+ ('date_done', '<=', deadline),
+ ('date_cancelled', '<=', deadline),
('channel', '=', channel.complete_name)],
)
if jobs:
@@ -400,6 +411,20 @@ def set_done(self):
return {'type': 'ir.actions.act_window_close'}
+class SetJobsToCancelled(models.TransientModel):
+ _inherit = 'queue.requeue.job'
+ _name = 'queue.jobs.to.cancelled'
+ _description = 'Cancel all selected jobs'
+
+ @api.multi
+ def set_cancelled(self):
+ jobs = self.job_ids.filtered(
+ lambda x: x.state in ('pending', 'failed', 'enqueued')
+ )
+ jobs.button_cancelled()
+ return {'type': 'ir.actions.act_window_close'}
+
+
class JobChannel(models.Model):
_name = 'queue.job.channel'
_description = 'Job Channels'
diff --git a/queue_job/tests/__init__.py b/queue_job/tests/__init__.py
index 10138c469e..a556f10d83 100644
--- a/queue_job/tests/__init__.py
+++ b/queue_job/tests/__init__.py
@@ -4,3 +4,4 @@
from . import test_model_job_channel
from . import test_model_job_function
from . import test_queue_job_protected_write
+from . import test_wizards
diff --git a/queue_job/tests/test_wizards.py b/queue_job/tests/test_wizards.py
new file mode 100644
index 0000000000..d03692ce61
--- /dev/null
+++ b/queue_job/tests/test_wizards.py
@@ -0,0 +1,39 @@
+# license lgpl-3.0 or later (http://www.gnu.org/licenses/lgpl.html)
+from odoo.tests import common
+
+
+class TestWizards(common.TransactionCase):
+ def setUp(self):
+ super().setUp()
+ self.job = self.env['queue.job'].with_context(
+ _job_edit_sentinel=self.env['queue.job'].EDIT_SENTINEL,
+ ).create({
+ 'uuid': 'test',
+ 'user_id': self.env.user.id,
+ 'state': 'failed',
+ 'model_name':
+ 'queue.job',
+ 'method_name': 'write',
+ 'args': (),
+ })
+
+ def _wizard(self, model_name):
+ return self.env[model_name].with_context(
+ active_model=self.job._name,
+ active_ids=self.job.ids,
+ ).create({})
+
+ def test_01_requeue(self):
+ wizard = self._wizard('queue.requeue.job')
+ wizard.requeue()
+ self.assertEqual(self.job.state, 'pending')
+
+ def test_02_cancel(self):
+ wizard = self._wizard('queue.jobs.to.cancelled')
+ wizard.set_cancelled()
+ self.assertEqual(self.job.state, 'cancelled')
+
+ def test_03_done(self):
+ wizard = self._wizard('queue.jobs.to.done')
+ wizard.set_done()
+ self.assertEqual(self.job.state, 'done')
diff --git a/queue_job/views/queue_job_views.xml b/queue_job/views/queue_job_views.xml
index b8e4d33fe5..c598c992eb 100644
--- a/queue_job/views/queue_job_views.xml
+++ b/queue_job/views/queue_job_views.xml
@@ -20,6 +20,12 @@
string="Set to 'Done'"
type="object"
groups="queue_job.group_queue_job_manager"/>
+
+ statusbar_colors='{"failed":"red","done":"green","cancelled":"yellow"}'/>
@@ -229,6 +235,22 @@
+
+ Cancel Jobs
+ queue.jobs.to.cancelled
+
+
+
+
+
Requeue Jobs
queue.requeue.job
@@ -249,6 +271,16 @@
+
+ Cancel jobs
+ queue.jobs.to.cancelled
+ form
+ form
+
+ new
+
+
+
queue.job.channel.form
queue.job.channel