diff --git a/queue_job/__manifest__.py b/queue_job/__manifest__.py index a202e87b46..1e3624d0dc 100644 --- a/queue_job/__manifest__.py +++ b/queue_job/__manifest__.py @@ -17,6 +17,7 @@ "views/queue_job_channel_views.xml", "views/queue_job_function_views.xml", "wizards/queue_jobs_to_done_views.xml", + "wizards/queue_jobs_to_cancelled_views.xml", "wizards/queue_requeue_job_views.xml", "views/queue_job_menus.xml", "data/queue_data.xml", diff --git a/queue_job/job.py b/queue_job/job.py index a4dc224b85..8efa05c73e 100644 --- a/queue_job/job.py +++ b/queue_job/job.py @@ -16,6 +16,7 @@ PENDING = "pending" ENQUEUED = "enqueued" +CANCELLED = "cancelled" DONE = "done" STARTED = "started" FAILED = "failed" @@ -25,6 +26,7 @@ (ENQUEUED, "Enqueued"), (STARTED, "Started"), (DONE, "Done"), + (CANCELLED, "Cancelled"), (FAILED, "Failed"), ] @@ -301,6 +303,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 @@ -484,6 +489,7 @@ def __init__( self.date_enqueued = None self.date_started = None self.date_done = None + self.date_cancelled = None self.result = None self.exc_name = None @@ -558,6 +564,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, @@ -571,6 +578,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: @@ -719,6 +728,7 @@ def set_pending(self, result=None, reset_retry=True): self.date_started = None self.date_done = None self.worker_pid = None + self.date_cancelled = None if reset_retry: self.retry = 0 if result is not None: @@ -743,6 +753,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 2d8ef74538..b6f8b52a6e 100644 --- a/queue_job/models/queue_job.py +++ b/queue_job/models/queue_job.py @@ -8,7 +8,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__) @@ -82,6 +82,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") @@ -187,6 +188,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() @@ -196,6 +199,11 @@ def button_done(self): self._change_job_state(DONE, result=result) return True + def button_cancelled(self): + result = _("Cancelled by %s") % self.env.user.name + self._change_job_state(CANCELLED, result=result) + return True + def requeue(self): self._change_job_state(PENDING) return True @@ -255,7 +263,9 @@ def autovacuum(self): while True: jobs = self.search( [ + "|", ("date_done", "<=", deadline), + ("date_cancelled", "<=", deadline), ("channel", "=", channel.complete_name), ], limit=1000, diff --git a/queue_job/security/ir.model.access.csv b/queue_job/security/ir.model.access.csv index 9242305158..634daf8ede 100644 --- a/queue_job/security/ir.model.access.csv +++ b/queue_job/security/ir.model.access.csv @@ -4,3 +4,4 @@ access_queue_job_function_manager,queue job functions manager,queue_job.model_qu access_queue_job_channel_manager,queue job channel manager,queue_job.model_queue_job_channel,queue_job.group_queue_job_manager,1,1,1,1 access_queue_requeue_job,queue requeue job manager,queue_job.model_queue_requeue_job,queue_job.group_queue_job_manager,1,1,1,1 access_queue_jobs_to_done,queue jobs to done manager,queue_job.model_queue_jobs_to_done,queue_job.group_queue_job_manager,1,1,1,1 +access_queue_jobs_to_cancelled,queue jobs to cancelled manager,queue_job.model_queue_jobs_to_cancelled,queue_job.group_queue_job_manager,1,1,1,1 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..2ac162d313 --- /dev/null +++ b/queue_job/tests/test_wizards.py @@ -0,0 +1,48 @@ +# 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 cb7aeac28b..9121e1b188 100644 --- a/queue_job/views/queue_job_views.xml +++ b/queue_job/views/queue_job_views.xml @@ -23,12 +23,20 @@ type="object" groups="queue_job.group_queue_job_manager" /> +