Skip to content

Commit ae93d45

Browse files
committed
[IMP] queue_job_cron: Avoid parallel run
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
1 parent cefb0a8 commit ae93d45

3 files changed

Lines changed: 50 additions & 10 deletions

File tree

queue_job_cron/models/ir_cron.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,23 @@
44

55
from odoo import api, fields, models
66

7+
from odoo.addons.queue_job.job import identity_exact
8+
79
_logger = logging.getLogger(__name__)
810

911

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

15+
no_parallel_queue_job_run = fields.Boolean(
16+
help="Avoid parallel run. "
17+
"If the cron job is already running, the new one will be skipped. "
18+
"By default, odoo never runs the same cron job in parallel. This "
19+
"option is therefore set to True by default when job is run as a "
20+
"queue job.",
21+
default=True,
22+
)
23+
1324
run_as_queue_job = fields.Boolean(
1425
help="Specify if this cron should be ran as a queue job"
1526
)
@@ -39,23 +50,29 @@ def method_direct_trigger(self):
3950
_cron = cron.with_user(cron.user_id).with_context(
4051
lastcall=cron.lastcall
4152
)
42-
_cron.with_delay(
43-
priority=_cron.priority,
44-
description=_cron.name,
45-
channel=_cron.channel_id.complete_name,
46-
)._run_job_as_queue_job(server_action=_cron.ir_actions_server_id)
53+
_cron._delay_run_job_as_queue_job(
54+
server_action=_cron.ir_actions_server_id
55+
)
4756
return True
4857

4958
def _callback(self, cron_name, server_action_id, job_id):
5059
cron = self.env["ir.cron"].sudo().browse(job_id)
5160
if cron.run_as_queue_job:
5261
server_action = self.env["ir.actions.server"].browse(server_action_id)
53-
return self.with_delay(
54-
priority=cron.priority,
55-
description=cron.name,
56-
channel=cron.channel_id.complete_name,
57-
)._run_job_as_queue_job(server_action=server_action)
62+
return cron._delay_run_job_as_queue_job(server_action=server_action)
5863
else:
5964
return super()._callback(
6065
cron_name=cron_name, server_action_id=server_action_id, job_id=job_id
6166
)
67+
68+
def _delay_run_job_as_queue_job(self, server_action):
69+
self.ensure_one()
70+
identity_key = None
71+
if self.no_parallel_queue_job_run:
72+
identity_key = identity_exact
73+
return self.with_delay(
74+
priority=self.priority,
75+
description=self.name,
76+
channel=self.channel_id.complete_name,
77+
identity_key=identity_key,
78+
)._run_job_as_queue_job(server_action=server_action)

queue_job_cron/tests/test_queue_job_cron.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,22 @@ def test_queue_job_cron_run(self):
3939
cron = self.env.ref("queue_job.ir_cron_autovacuum_queue_jobs")
4040
IrCron = self.env["ir.cron"]
4141
IrCron._run_job_as_queue_job(server_action=cron.ir_actions_server_id)
42+
43+
def test_queue_job_no_parallelism(self):
44+
cron = self.env.ref("queue_job.ir_cron_autovacuum_queue_jobs")
45+
default_channel = self.env.ref("queue_job_cron.channel_root_ir_cron")
46+
cron.write(
47+
{
48+
"no_parallel_queue_job_run": True,
49+
"run_as_queue_job": True,
50+
"channel_id": default_channel.id,
51+
}
52+
)
53+
cron.method_direct_trigger()
54+
cron.method_direct_trigger()
55+
nb_jobs = self.env["queue.job"].search_count([("name", "=", cron.name)])
56+
self.assertEqual(nb_jobs, 1)
57+
cron.no_parallel_queue_job_run = False
58+
cron.method_direct_trigger()
59+
nb_jobs = self.env["queue.job"].search_count([("name", "=", cron.name)])
60+
self.assertEqual(nb_jobs, 2)

queue_job_cron/views/ir_cron_view.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
<field name="arch" type="xml">
88
<field name="doall" position="after">
99
<field name="run_as_queue_job" />
10+
<field
11+
name="no_parallel_queue_job_run"
12+
attrs="{'invisible': [('run_as_queue_job', '=', False)]}"
13+
/>
1014
<field
1115
name="channel_id"
1216
attrs="{'invisible': [('run_as_queue_job', '=', False)],

0 commit comments

Comments
 (0)