Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions queue_job/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

PENDING = 'pending'
ENQUEUED = 'enqueued'
CANCELLED = 'cancelled'
DONE = 'done'
STARTED = 'started'
FAILED = 'failed'
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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():
Expand Down
29 changes: 27 additions & 2 deletions queue_job/models/queue_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)

Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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()
Expand All @@ -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)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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'
Expand Down
1 change: 1 addition & 0 deletions queue_job/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
39 changes: 39 additions & 0 deletions queue_job/tests/test_wizards.py
Original file line number Diff line number Diff line change
@@ -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')
34 changes: 33 additions & 1 deletion queue_job/views/queue_job_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,20 @@
string="Set to 'Done'"
type="object"
groups="queue_job.group_queue_job_manager"/>
<button name="button_cancelled"
states="pending,enqueued,failed"
class="oe_highlight"
string="Cancel job"
type="object"
groups="queue_job.group_queue_job_manager"/>
<button name="open_related_action"
string="Related"
type="object"
/>
<field name="state"
widget="statusbar"
statusbar_visible="pending,enqueued,started,done"
statusbar_colors='{"failed":"red","done":"green"}'/>
statusbar_colors='{"failed":"red","done":"green","cancelled":"yellow"}'/>
</header>
<sheet>
<h1>
Expand Down Expand Up @@ -229,6 +235,22 @@
</field>
</record>

<record id="view_set_jobs_cancelled" model="ir.ui.view">
<field name="name">Cancel Jobs</field>
<field name="model">queue.jobs.to.cancelled</field>
<field name="arch" type="xml">
<form>
<group string="The selected jobs will be cancelled.">
<field name="job_ids" nolabel="1"/>
</group>
<footer>
<button name="set_cancelled" string="Cancel jobs" type="object" class="oe_highlight"/>
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>

<record id="action_requeue_job" model="ir.actions.act_window">
<field name="name">Requeue Jobs</field>
<field name="res_model">queue.requeue.job</field>
Expand All @@ -249,6 +271,16 @@
<field name="binding_model_id" ref="queue_job.model_queue_job" />
</record>

<record id="action_set_jobs_cancelled" model="ir.actions.act_window">
<field name="name">Cancel jobs</field>
<field name="res_model">queue.jobs.to.cancelled</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_set_jobs_cancelled"/>
<field name="target">new</field>
<field name="binding_model_id" ref="queue_job.model_queue_job" />
</record>

<record id="view_queue_job_channel_form" model="ir.ui.view">
<field name="name">queue.job.channel.form</field>
<field name="model">queue.job.channel</field>
Expand Down