Skip to content
Closed
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
4 changes: 2 additions & 2 deletions queue_job/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

{
"name": "Job Queue",
"version": "14.0.1.3.1",
"version": "15.0.1.0.0",
"author": "Camptocamp,ACSONE SA/NV,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/queue",
"license": "LGPL-3",
Expand All @@ -22,7 +22,7 @@
"data/queue_data.xml",
"data/queue_job_function_data.xml",
],
"installable": False,
"installable": True,
"development_status": "Mature",
"maintainers": ["guewen"],
"post_init_hook": "post_init_hook",
Expand Down
27 changes: 11 additions & 16 deletions queue_job/controllers/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
from psycopg2 import OperationalError
from werkzeug.exceptions import Forbidden

import odoo
from odoo import _, http, tools
from odoo import SUPERUSER_ID, _, api, http, registry, tools
from odoo.service.model import PG_CONCURRENCY_ERRORS_TO_RETRY

from ..exception import FailedJobError, NothingToDoJob, RetryableJobError
Expand Down Expand Up @@ -39,17 +38,15 @@ def _try_perform_job(self, env, job):
@http.route("/queue_job/runjob", type="http", auth="none", save_session=False)
def runjob(self, db, job_uuid, **kw):
http.request.session.db = db
env = http.request.env(user=odoo.SUPERUSER_ID)
env = http.request.env(user=SUPERUSER_ID)

def retry_postpone(job, message, seconds=None):
job.env.clear()
with odoo.api.Environment.manage():
with odoo.registry(job.env.cr.dbname).cursor() as new_cr:
job.env = job.env(cr=new_cr)
job.postpone(result=message, seconds=seconds)
job.set_pending(reset_retry=False)
job.store()
new_cr.commit()
with registry(job.env.cr.dbname).cursor() as new_cr:
job.env = api.Environment(new_cr, SUPERUSER_ID, {})
job.postpone(result=message, seconds=seconds)
job.set_pending(reset_retry=False)
job.store()

# ensure the job to run is in the correct state and lock the record
env.cr.execute(
Expand Down Expand Up @@ -101,12 +98,10 @@ def retry_postpone(job, message, seconds=None):
traceback.print_exc(file=buff)
_logger.error(buff.getvalue())
job.env.clear()
with odoo.api.Environment.manage():
with odoo.registry(job.env.cr.dbname).cursor() as new_cr:
job.env = job.env(cr=new_cr)
job.set_failed(exc_info=buff.getvalue())
job.store()
new_cr.commit()
with registry(job.env.cr.dbname).cursor() as new_cr:
job.env = api.Environment(new_cr, SUPERUSER_ID, {})
job.set_failed(exc_info=buff.getvalue())
job.store()
raise

return ""
Expand Down
2 changes: 1 addition & 1 deletion queue_job/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class JobSerialized(fields.Field):
def __init__(self, string=fields.Default, base_type=fields.Default, **kwargs):
super().__init__(string=string, _base_type=base_type, **kwargs)

def _setup_attrs(self, model, name):
def _setup_attrs(self, model, name): # pylint: disable=W8110
super()._setup_attrs(model, name)
if self._base_type not in self._default_json_mapping:
raise ValueError("%s is not a supported base type" % (self._base_type))
Expand Down
2 changes: 1 addition & 1 deletion queue_job/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ def description(self):

@property
def uuid(self):
"""Job ID, this is an UUID """
"""Job ID, this is an UUID"""
if self._uuid is None:
self._uuid = str(uuid.uuid4())
return self._uuid
Expand Down
4 changes: 2 additions & 2 deletions queue_job/jobrunner/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def stop(self):


class WorkerJobRunner(server.Worker):
""" Jobrunner workers """
"""Jobrunner workers"""

def __init__(self, multi):
super().__init__(multi)
Expand All @@ -58,7 +58,7 @@ def __init__(self, multi):
def sleep(self):
pass

def signal_handler(self, sig, frame):
def signal_handler(self, sig, frame): # pylint: disable=W8110
_logger.debug("WorkerJobRunner (%s) received signal %s", self.pid, sig)
super().signal_handler(sig, frame)
self.runner.stop()
Expand Down
6 changes: 3 additions & 3 deletions queue_job/jobrunner/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ def set_running(self, job):
_logger.debug("job %s marked running in channel %s", job.uuid, self)

def set_failed(self, job):
"""Mark the job as failed. """
"""Mark the job as failed."""
if job not in self._failed:
self._queue.remove(job)
self._running.remove(job)
Expand Down Expand Up @@ -873,11 +873,11 @@ def parse_simple_config(cls, config_string):
capacity = config_items[1]
try:
config["capacity"] = int(capacity)
except Exception:
except Exception as ex:
raise ValueError(
"Invalid channel config %s: "
"invalid capacity %s" % (config_string, capacity)
)
) from ex
for config_item in config_items[2:]:
kv = split_strip(config_item, "=")
if len(kv) == 1:
Expand Down
2 changes: 1 addition & 1 deletion queue_job/models/queue_job_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class QueueJobChannel(models.Model):

name = fields.Char()
complete_name = fields.Char(
compute="_compute_complete_name", store=True, readonly=True
compute="_compute_complete_name", store=True, readonly=True, recursive=True
)
parent_id = fields.Many2one(
comodel_name="queue.job.channel", string="Parent Channel", ondelete="restrict"
Expand Down
24 changes: 16 additions & 8 deletions queue_job/models/queue_job_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import re
from collections import namedtuple

from odoo import _, api, exceptions, fields, models, tools
from odoo import SUPERUSER_ID, _, api, exceptions, fields, models, tools

from ..fields import JobSerialized

Expand Down Expand Up @@ -93,7 +93,11 @@ def _inverse_name(self):
raise exceptions.UserError(_("Invalid job function: {}").format(self.name))
model_name = groups[1]
method = groups[2]
model = self.env["ir.model"].search([("model", "=", model_name)], limit=1)
model = (
self.env["ir.model"]
.with_user(SUPERUSER_ID)
.search([("model", "=", model_name)], limit=1)
)
if not model:
raise exceptions.UserError(_("Model {} not found").format(model_name))
self.model_id = model.id
Expand All @@ -112,8 +116,10 @@ def _inverse_edit_retry_pattern(self):
self.retry_pattern = ast.literal_eval(edited)
else:
self.retry_pattern = {}
except (ValueError, TypeError, SyntaxError):
raise exceptions.UserError(self._retry_pattern_format_error_message())
except (ValueError, TypeError, SyntaxError) as ex:
raise exceptions.UserError(
self._retry_pattern_format_error_message()
) from ex

@api.depends("related_action")
def _compute_edit_related_action(self):
Expand All @@ -127,8 +133,10 @@ def _inverse_edit_related_action(self):
self.related_action = ast.literal_eval(edited)
else:
self.related_action = {}
except (ValueError, TypeError, SyntaxError):
raise exceptions.UserError(self._related_action_format_error_message())
except (ValueError, TypeError, SyntaxError) as ex:
raise exceptions.UserError(
self._related_action_format_error_message()
) from ex

@staticmethod
def job_function_name(model_name, method_name):
Expand Down Expand Up @@ -193,10 +201,10 @@ def _check_retry_pattern(self):
for value in all_values:
try:
int(value)
except ValueError:
except ValueError as ex:
raise exceptions.UserError(
record._retry_pattern_format_error_message()
)
) from ex

def _related_action_format_error_message(self):
return _(
Expand Down
9 changes: 6 additions & 3 deletions queue_job/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,17 @@ class OdooDocTestCase(doctest.DocTestCase):
- output a more meaningful test name than default "DocTestCase.runTest"
"""

def __init__(self, doctest, optionflags=0, setUp=None, tearDown=None, checker=None):
def __init__(
self, doctest, optionflags=0, setUp=None, tearDown=None, checker=None, seq=0
):
super().__init__(
doctest._dt_test,
optionflags=optionflags,
setUp=setUp,
tearDown=tearDown,
checker=checker,
)
self.test_sequence = seq

def setUp(self):
"""Log an extra statement which test is started."""
Expand All @@ -139,8 +142,8 @@ def load_tests(loader, tests, ignore):
doctest.DocTestCase.doClassCleanups = lambda: None
doctest.DocTestCase.tearDown_exceptions = []

for test in doctest.DocTestSuite(module):
odoo_test = OdooDocTestCase(test)
for idx, test in enumerate(doctest.DocTestSuite(module)):
odoo_test = OdooDocTestCase(test, seq=idx)
odoo_test.test_tags = {"standard", "at_install", "queue_job", "doctest"}
tests.addTest(odoo_test)

Expand Down
17 changes: 13 additions & 4 deletions queue_job/tests/test_model_job_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,20 @@ def test_channel_complete_name_uniq(self):
self.assertEqual(channel.complete_name, "root.sub")

self.Channel.create({"name": "sub", "parent_id": self.root_channel.id})
with self.assertRaises(IntegrityError):
# Flush process all the pending recomputations (or at least the
# given field and flush the pending updates to the database.
# It is normally called on commit.

# Flush process all the pending recomputations (or at least the
# given field and flush the pending updates to the database.
# It is normally called on commit.

# The context manager 'with self.assertRaises(IntegrityError)' purposefully
# not uses here due to its 'flush()' method inside it and exception raises
# before the line 'self.env["base"].flush()'. So, we are expecting an IntegrityError.
try:
self.env["base"].flush()
except IntegrityError as ex:
self.assertIn("queue_job_channel_name_uniq", ex.pgerror)
else:
self.assertEqual(True, False)

def test_channel_name_get(self):
channel = self.Channel.create(
Expand Down
2 changes: 1 addition & 1 deletion queue_job/tests/test_model_job_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from odoo.tests import common


class TestJobFunction(common.SavepointCase):
class TestJobFunction(common.TransactionCase):
def test_function_name_compute(self):
function = self.env["queue.job.function"].create(
{"model_id": self.env.ref("base.model_res_users").id, "method": "read"}
Expand Down
2 changes: 1 addition & 1 deletion queue_job/tests/test_queue_job_protected_write.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from odoo.tests import common


class TestJobWriteProtected(common.SavepointCase):
class TestJobWriteProtected(common.TransactionCase):
def test_create_error(self):
with self.assertRaises(exceptions.AccessError):
self.env["queue.job"].create(
Expand Down
2 changes: 1 addition & 1 deletion test_queue_job/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
"data/queue_job_function_data.xml",
"security/ir.model.access.csv",
],
"installable": False,
"installable": True,
}