Skip to content

Commit c57db4d

Browse files
committed
Merge PR #971 into 18.0
Signed-off-by simahawk
2 parents 6ccb8ce + 2f7a155 commit c57db4d

7 files changed

Lines changed: 66 additions & 2 deletions

File tree

queue_job/controllers/main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ def retry_postpone(job, message, seconds=None):
186186
vals = cls._get_failure_values(job, traceback_txt, orig_exception)
187187
job.set_failed(**vals)
188188
job.store()
189+
job.on_fail(vals)
189190
buff.close()
190191
raise
191192

queue_job/job.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,12 @@ def __init__(
430430
self.job_config = (
431431
self.env["queue.job.function"].sudo().job_config(self.job_function_name)
432432
)
433+
on_fail_method_name = self.job_config.on_fail_method_name
434+
if on_fail_method_name and not _is_model_method(
435+
getattr(self.recordset, on_fail_method_name, None)
436+
):
437+
raise TypeError("Job accepts only methods of Models")
438+
self.on_fail_method_name = on_fail_method_name
433439

434440
self.state = PENDING
435441

@@ -868,6 +874,13 @@ def set_failed(self, **kw):
868874
if v is not None:
869875
setattr(self, k, v)
870876

877+
def on_fail(self, fail_vals):
878+
if not self.on_fail_method_name:
879+
return
880+
on_fail_func = getattr(self.recordset, self.on_fail_method_name, None)
881+
if on_fail_func:
882+
on_fail_func(**fail_vals)
883+
871884
def __repr__(self):
872885
return "<Job %s, priority:%d>" % (self.uuid, self.priority)
873886

queue_job/models/queue_job.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,3 +485,6 @@ def _test_job(
485485
time.sleep(job_duration)
486486
if commit_within_job:
487487
self.env.cr.commit() # pylint: disable=invalid-commit
488+
489+
def _test_on_fail(self, **kw):
490+
pass

queue_job/models/queue_job_function.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ class QueueJobFunction(models.Model):
2929
"related_action_func_name "
3030
"related_action_kwargs "
3131
"job_function_id "
32-
"allow_commit",
32+
"allow_commit "
33+
"on_fail_method_name",
3334
)
3435

3536
def _default_channel(self):
@@ -48,6 +49,10 @@ def _default_channel(self):
4849
comodel_name="ir.model", string="Model", ondelete="cascade"
4950
)
5051
method = fields.Char()
52+
on_fail_method = fields.Char(
53+
help="Model function to be called if the job is failed and will not be "
54+
"retried.",
55+
)
5156

5257
channel_id = fields.Many2one(
5358
comodel_name="queue.job.channel",
@@ -157,6 +162,7 @@ def job_default_config(self):
157162
related_action_kwargs={},
158163
job_function_id=None,
159164
allow_commit=False,
165+
on_fail_method_name=None,
160166
)
161167

162168
def _parse_retry_pattern(self):
@@ -193,6 +199,7 @@ def job_config(self, name):
193199
related_action_kwargs=config.related_action.get("kwargs", {}),
194200
job_function_id=config.id,
195201
allow_commit=config.allow_commit,
202+
on_fail_method_name=config.on_fail_method,
196203
)
197204

198205
def _retry_pattern_format_error_message(self):

queue_job/tests/test_model_job_function.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def test_function_job_config(self):
3535
{
3636
"model_id": self.env.ref("base.model_res_users").id,
3737
"method": "read",
38+
"on_fail_method": "search_read",
3839
"channel_id": channel.id,
3940
"edit_retry_pattern": "{1: 2, 3: 4}",
4041
"edit_related_action": (
@@ -55,5 +56,6 @@ def test_function_job_config(self):
5556
related_action_kwargs={"b": 1},
5657
job_function_id=job_function.id,
5758
allow_commit=True,
59+
on_fail_method_name="search_read",
5860
),
5961
)

queue_job/tests/test_run_rob_controller.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
2+
from unittest.mock import patch
23

34
from odoo.tests.common import TransactionCase
5+
from odoo.tools import mute_logger
46

57
from ..controllers.main import RunJobController
8+
from ..exception import JobError
69
from ..job import Job
710

811

912
class TestRunJobController(TransactionCase):
13+
def setUp(self):
14+
super().setUp()
15+
16+
def _clean_queue_job():
17+
self.env["queue.job"].search([]).unlink()
18+
19+
self.addCleanup(_clean_queue_job)
20+
1021
def test_get_failure_values(self):
1122
method = self.env["res.users"].mapped
1223
job = Job(method)
@@ -21,3 +32,31 @@ def test_runjob_success(self):
2132
RunJobController._runjob(self.env, job)
2233
self.assertEqual(job.state, "done")
2334
self.assertEqual(job.db_record().state, "done")
35+
36+
def test_runjob_on_fail(self):
37+
function = self.env.ref("queue_job.job_function_queue_job__test_job")
38+
function.on_fail_method = "_test_on_fail"
39+
job = self.env["queue.job"].with_delay()._test_job(failure_rate=1)
40+
with (
41+
self.assertRaises(JobError),
42+
patch(
43+
"odoo.addons.queue_job.models.queue_job.QueueJob._test_on_fail"
44+
) as mocked_hook,
45+
patch("odoo.addons.queue_job.job.Job.in_temporary_env") as mocked_temp_env,
46+
mute_logger("odoo.addons.queue_job.controllers.main"),
47+
):
48+
mocked_temp_env.return_value.__enter__.return_value = self.env
49+
RunJobController._runjob(self.env, job)
50+
self.assertEqual(job.state, "failed")
51+
self.assertEqual(mocked_hook.call_count, 1)
52+
53+
def test_runjob_on_fail_not_configured(self):
54+
job = self.env["queue.job"].with_delay()._test_job(failure_rate=1)
55+
with (
56+
self.assertRaises(JobError),
57+
patch("odoo.addons.queue_job.job.Job.in_temporary_env") as mocked_temp_env,
58+
mute_logger("odoo.addons.queue_job.controllers.main"),
59+
):
60+
mocked_temp_env.return_value.__enter__.return_value = self.env
61+
RunJobController._runjob(self.env, job)
62+
self.assertEqual(job.state, "failed")

test_queue_job/tests/test_autovacuum.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ def test_autovacuum_multi_channel(self):
5151
job_60days.write(
5252
{"channel": channel_60days.complete_name, "date_done": date_done}
5353
)
54-
5554
self.assertEqual(
5655
len(self.env["queue.job"].search([("channel", "!=", False)])), 2
5756
)

0 commit comments

Comments
 (0)