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
2 changes: 0 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ exclude: |
# NOT INSTALLABLE ADDONS
^base_export_async/|
^base_import_async/|
^queue_job/|
^queue_job_cron/|
^queue_job_subscribe/|
^test_base_import_async/|
^test_queue_job/|
# END NOT INSTALLABLE ADDONS
# Files and folders generated by bots, to avoid loops
^setup/|/static/description/index\.html$|
Expand Down
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=missing-return
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=missing-return
_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
20 changes: 13 additions & 7 deletions queue_job/models/queue_job_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ 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"].sudo().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 +114,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 +131,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 +199,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
1 change: 1 addition & 0 deletions setup/queue_job/odoo/addons/queue_job
6 changes: 6 additions & 0 deletions setup/queue_job/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
1 change: 1 addition & 0 deletions setup/test_queue_job/odoo/addons/test_queue_job
6 changes: 6 additions & 0 deletions setup/test_queue_job/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
4 changes: 2 additions & 2 deletions test_queue_job/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

{
"name": "Queue Job Tests",
"version": "14.0.1.3.0",
"version": "15.0.1.0.0",
"author": "Camptocamp,Odoo Community Association (OCA)",
"license": "LGPL-3",
"category": "Generic Modules",
Expand All @@ -14,5 +14,5 @@
"data/queue_job_function_data.xml",
"security/ir.model.access.csv",
],
"installable": False,
"installable": True,
}
11 changes: 6 additions & 5 deletions test_queue_job/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@


class JobCommonCase(common.TransactionCase):
def setUp(self):
super().setUp()
self.queue_job = self.env["queue.job"]
self.user = self.env["res.users"]
self.method = self.env["test.queue.job"].testing_method
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.queue_job = cls.env["queue.job"]
cls.user = cls.env["res.users"]
cls.method = cls.env["test.queue.job"].testing_method

def _create_job(self):
test_job = Job(self.method)
Expand Down
7 changes: 4 additions & 3 deletions test_queue_job/tests/test_autovacuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@


class TestQueueJobAutovacuumCronJob(JobCommonCase):
def setUp(self):
super().setUp()
self.cron_job = self.env.ref("queue_job.ir_cron_autovacuum_queue_jobs")
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.cron_job = cls.env.ref("queue_job.ir_cron_autovacuum_queue_jobs")

def test_old_jobs_are_deleted_by_cron_job(self):
"""Old jobs are deleted by the autovacuum cron job."""
Expand Down
Loading