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: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ addon | version | maintainers | summary
--- | --- | --- | ---
[base_export_async](base_export_async/) | 16.0.1.1.0 | | Asynchronous export with job queue
[base_import_async](base_import_async/) | 16.0.1.2.0 | | Import CSV files in the background
[queue_job](queue_job/) | 16.0.2.10.0 | [![guewen](https://github.com/guewen.png?size=30px)](https://github.com/guewen) | Job Queue
[queue_job](queue_job/) | 16.0.2.11.0 | [![guewen](https://github.com/guewen.png?size=30px)](https://github.com/guewen) | Job Queue
[queue_job_batch](queue_job_batch/) | 16.0.1.0.1 | | Job Queue Batch
[queue_job_cron](queue_job_cron/) | 16.0.2.1.0 | | Scheduled Actions as Queue Jobs
[queue_job_cron_jobrunner](queue_job_cron_jobrunner/) | 16.0.1.1.0 | [![ivantodorovich](https://github.com/ivantodorovich.png?size=30px)](https://github.com/ivantodorovich) | Run jobs without a dedicated JobRunner
Expand Down
2 changes: 1 addition & 1 deletion queue_job/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Job Queue
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:3122e45d99a3e3ce7c38316fbec4714e530da80fd806bcdfff9aa934c4ec0bdb
!! source digest: sha256:71335b8e2973a1871cf0bf504860c2af79d7d15f8c6e39d237f0c396f0b46e9f
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Mature-brightgreen.png
Expand Down
2 changes: 1 addition & 1 deletion queue_job/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

{
"name": "Job Queue",
"version": "16.0.2.10.0",
"version": "16.0.2.11.0",
"author": "Camptocamp,ACSONE SA/NV,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/queue",
"license": "LGPL-3",
Expand Down
21 changes: 10 additions & 11 deletions queue_job/i18n/de.po
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-03-03 18:06+0000\n"
"PO-Revision-Date: 2025-03-17 19:06+0000\n"
"Last-Translator: davidbeckercbl <becker@cbl-computer.de>\n"
"Language-Team: none\n"
"Language: de\n"
Expand Down Expand Up @@ -692,7 +692,7 @@ msgstr "Job einreihen"
#. module: queue_job
#: model:ir.model,name:queue_job.model_queue_job_lock
msgid "Queue Job Lock"
msgstr ""
msgstr "Job einreihen Sperre"

#. module: queue_job
#. odoo-python
Expand All @@ -708,9 +708,8 @@ msgstr "Datensatz"

#. module: queue_job
#: model:ir.model.fields,field_description:queue_job.field_queue_job__records
#, fuzzy
msgid "Record(s)"
msgstr "Datensatz"
msgstr "Datensatz/Datensätze"

#. module: queue_job
#: model_terms:ir.ui.view,arch_db:queue_job.view_queue_job_form
Expand Down Expand Up @@ -744,7 +743,7 @@ msgstr "Zugehörige Datensätze"
#. module: queue_job
#: model_terms:ir.ui.view,arch_db:queue_job.view_queue_job_tree
msgid "Remaining days to execute"
msgstr ""
msgstr "Verbleibende Tage bis zur Ausführung"

#. module: queue_job
#: model:ir.model.fields,field_description:queue_job.field_queue_job_channel__removal_interval
Expand Down Expand Up @@ -781,17 +780,17 @@ msgstr "Ergebnis"
#. module: queue_job
#: model_terms:ir.ui.view,arch_db:queue_job.view_queue_job_form
msgid "Results"
msgstr ""
msgstr "Ergebnisse"

#. module: queue_job
#: model:ir.model.fields,field_description:queue_job.field_queue_job_function__edit_retry_pattern
msgid "Retry Pattern"
msgstr ""
msgstr "Wiederholungsmuster"

#. module: queue_job
#: model:ir.model.fields,field_description:queue_job.field_queue_job_function__retry_pattern
msgid "Retry Pattern (serialized)"
msgstr ""
msgstr "Wiederholungsmuster (serialisiert)"

#. module: queue_job
#: model:ir.model,name:queue_job.model_queue_jobs_to_done
Expand Down Expand Up @@ -893,7 +892,7 @@ msgstr ""
#. module: queue_job
#: model_terms:ir.ui.view,arch_db:queue_job.view_set_jobs_cancelled
msgid "The selected jobs will be cancelled."
msgstr ""
msgstr "Die markierten Jobs werden abgebrochen."

#. module: queue_job
#: model_terms:ir.ui.view,arch_db:queue_job.view_requeue_job
Expand Down Expand Up @@ -958,7 +957,7 @@ msgstr "Benutzer"
#: model:ir.model.fields.selection,name:queue_job.selection__queue_job__state__wait_dependencies
#: model_terms:ir.ui.view,arch_db:queue_job.view_queue_job_search
msgid "Wait Dependencies"
msgstr ""
msgstr "Warten Abhängigkeiten"

#. module: queue_job
#: model:ir.model,name:queue_job.model_queue_requeue_job
Expand All @@ -968,7 +967,7 @@ msgstr "Assistent zur erneuten Einreihung einer Job-Auswahl"
#. module: queue_job
#: model:ir.model.fields,field_description:queue_job.field_queue_job__worker_pid
msgid "Worker Pid"
msgstr ""
msgstr "Arbeiter Prozess-Id"

#, python-format
#~ msgid "If both parameters are 0, ALL jobs will be requeued!"
Expand Down
41 changes: 35 additions & 6 deletions queue_job/jobrunner/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,17 @@

SELECT_TIMEOUT = 60
ERROR_RECOVERY_DELAY = 5
PG_ADVISORY_LOCK_ID = 2293787760715711918

_logger = logging.getLogger(__name__)

select = selectors.DefaultSelector


class MasterElectionLost(Exception):
pass


# Unfortunately, it is not possible to extend the Odoo
# server command line arguments, so we resort to environment variables
# to configure the runner (channels mostly).
Expand Down Expand Up @@ -227,10 +232,15 @@ def __init__(self, db_name):
self.db_name = db_name
connection_info = _connection_info_for(db_name)
self.conn = psycopg2.connect(**connection_info)
self.conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
self.has_queue_job = self._has_queue_job()
if self.has_queue_job:
self._initialize()
try:
self.conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
self.has_queue_job = self._has_queue_job()
if self.has_queue_job:
self._acquire_master_lock()
self._initialize()
except BaseException:
self.close()
raise

def close(self):
# pylint: disable=except-pass
Expand All @@ -243,6 +253,14 @@ def close(self):
pass
self.conn = None

def _acquire_master_lock(self):
"""Acquire the master runner lock or raise MasterElectionLost"""
with closing(self.conn.cursor()) as cr:
cr.execute("SELECT pg_try_advisory_lock(%s)", (PG_ADVISORY_LOCK_ID,))
if not cr.fetchone()[0]:
msg = f"could not acquire master runner lock on {self.db_name}"
raise MasterElectionLost(msg)

def _has_queue_job(self):
with closing(self.conn.cursor()) as cr:
cr.execute(
Expand Down Expand Up @@ -461,14 +479,17 @@ def close_databases(self, remove_jobs=True):
self.db_by_name = {}

def initialize_databases(self):
for db_name in self.get_db_names():
for db_name in sorted(self.get_db_names()):
# sorting is important to avoid deadlocks in acquiring the master lock
db = Database(db_name)
if db.has_queue_job:
self.db_by_name[db_name] = db
with db.select_jobs("state in %s", (NOT_DONE,)) as cr:
for job_data in cr:
self.channel_manager.notify(db_name, *job_data)
_logger.info("queue job runner ready for db %s", db_name)
else:
db.close()

def requeue_dead_jobs(self):
for db in self.db_by_name.values():
Expand Down Expand Up @@ -560,7 +581,7 @@ def run(self):
while not self._stop:
# outer loop does exception recovery
try:
_logger.info("initializing database connections")
_logger.debug("initializing database connections")
# TODO: how to detect new databases or databases
# on which queue_job is installed after server start?
self.initialize_databases()
Expand All @@ -576,6 +597,14 @@ def run(self):
except InterruptedError:
# Interrupted system call, i.e. KeyboardInterrupt during select
self.stop()
except MasterElectionLost as e:
_logger.debug(
"master election lost: %s, sleeping %ds and retrying",
e,
ERROR_RECOVERY_DELAY,
)
self.close_databases()
time.sleep(ERROR_RECOVERY_DELAY)
except Exception:
_logger.exception(
"exception: sleeping %ds and retrying", ERROR_RECOVERY_DELAY
Expand Down
2 changes: 1 addition & 1 deletion queue_job/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ <h1 class="title">Job Queue</h1>
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:3122e45d99a3e3ce7c38316fbec4714e530da80fd806bcdfff9aa934c4ec0bdb
!! source digest: sha256:71335b8e2973a1871cf0bf504860c2af79d7d15f8c6e39d237f0c396f0b46e9f
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Mature" src="https://img.shields.io/badge/maturity-Mature-brightgreen.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/queue/tree/16.0/queue_job"><img alt="OCA/queue" src="https://img.shields.io/badge/github-OCA%2Fqueue-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/queue-16-0/queue-16-0-queue_job"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/queue&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This addon adds an integrated Job Queue to Odoo.</p>
Expand Down