Skip to content

Commit

Permalink
[IMP] queue_job_cron: Avoid parallel run
Browse files Browse the repository at this point in the history
By default, odoo never runs the same cron job in parallel. This commit uses the identity key mechanism to enforce this mechanism when a cron job is run as a queue job. This behaviour can be controlled by a new setting on the cron definition but is activated by default to keep the original behaviour
  • Loading branch information
lmignon committed Dec 21, 2023
1 parent cefb0a8 commit 6d0550c
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 10 deletions.
37 changes: 27 additions & 10 deletions queue_job_cron/models/ir_cron.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@

from odoo import api, fields, models

from odoo.addons.queue_job.job import identity_exact

_logger = logging.getLogger(__name__)


class IrCron(models.Model):
_inherit = "ir.cron"

no_parallel_queue_job_run = fields.Boolean(
help="Avoid parallel run. "
"If the cron job is already running, the new one will be skipped. "
"By default, odoo never runs the same cron job in parallel. This "
"option is therefore set to True by default when job is run as a "
"queue job.",
default=True,
)

run_as_queue_job = fields.Boolean(
help="Specify if this cron should be ran as a queue job"
)
Expand Down Expand Up @@ -39,23 +50,29 @@ def method_direct_trigger(self):
_cron = cron.with_user(cron.user_id).with_context(
lastcall=cron.lastcall
)
_cron.with_delay(
priority=_cron.priority,
description=_cron.name,
channel=_cron.channel_id.complete_name,
)._run_job_as_queue_job(server_action=_cron.ir_actions_server_id)
_cron._delay_run_job_as_queue_job(
server_action=_cron.ir_actions_server_id
)
return True

def _callback(self, cron_name, server_action_id, job_id):
cron = self.env["ir.cron"].sudo().browse(job_id)
if cron.run_as_queue_job:
server_action = self.env["ir.actions.server"].browse(server_action_id)
return self.with_delay(
priority=cron.priority,
description=cron.name,
channel=cron.channel_id.complete_name,
)._run_job_as_queue_job(server_action=server_action)
return cron._delay_run_job_as_queue_job(server_action=server_action)

Check warning on line 62 in queue_job_cron/models/ir_cron.py

View check run for this annotation

Codecov / codecov/patch

queue_job_cron/models/ir_cron.py#L62

Added line #L62 was not covered by tests
else:
return super()._callback(
cron_name=cron_name, server_action_id=server_action_id, job_id=job_id
)

def _delay_run_job_as_queue_job(self, server_action):
self.ensure_one()
identity_key = None
if self.no_parallel_queue_job_run:
identity_key = identity_exact
return self.with_delay(
priority=self.priority,
description=self.name,
channel=self.channel_id.complete_name,
identity_key=identity_key,
)._run_job_as_queue_job(server_action=server_action)
Empty file.
9 changes: 9 additions & 0 deletions queue_job_cron/readme/newsfragments/612.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
By default prevent parallel run of the same cron job when run as queue job.

When a cron job is run by odoo, the odoo runner will prevent parallel run
of the same cron job. Before this change, this was not the case when the
cron job was run as a queue job. A new option is added to the cron job when
run as a queue job to prevent parallel run. This option is set to True by
default. In this way, the behavior is now the same as when the cron job is run
by odoo but you keep the possibility to disable this restriction when run as
a queue job.
19 changes: 19 additions & 0 deletions queue_job_cron/tests/test_queue_job_cron.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,22 @@ def test_queue_job_cron_run(self):
cron = self.env.ref("queue_job.ir_cron_autovacuum_queue_jobs")
IrCron = self.env["ir.cron"]
IrCron._run_job_as_queue_job(server_action=cron.ir_actions_server_id)

def test_queue_job_no_parallelism(self):
cron = self.env.ref("queue_job.ir_cron_autovacuum_queue_jobs")
default_channel = self.env.ref("queue_job_cron.channel_root_ir_cron")
cron.write(
{
"no_parallel_queue_job_run": True,
"run_as_queue_job": True,
"channel_id": default_channel.id,
}
)
cron.method_direct_trigger()
cron.method_direct_trigger()
nb_jobs = self.env["queue.job"].search_count([("name", "=", cron.name)])
self.assertEqual(nb_jobs, 1)
cron.no_parallel_queue_job_run = False
cron.method_direct_trigger()
nb_jobs = self.env["queue.job"].search_count([("name", "=", cron.name)])
self.assertEqual(nb_jobs, 2)
4 changes: 4 additions & 0 deletions queue_job_cron/views/ir_cron_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
<field name="arch" type="xml">
<field name="doall" position="after">
<field name="run_as_queue_job" />
<field
name="no_parallel_queue_job_run"
attrs="{'invisible': [('run_as_queue_job', '=', False)]}"
/>
<field
name="channel_id"
attrs="{'invisible': [('run_as_queue_job', '=', False)],
Expand Down

0 comments on commit 6d0550c

Please sign in to comment.