diff --git a/README.md b/README.md index bf1673ecf0..42c24dad52 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/queue_job/README.rst b/queue_job/README.rst index a0b8c4afde..49092aee44 100644 --- a/queue_job/README.rst +++ b/queue_job/README.rst @@ -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 diff --git a/queue_job/__manifest__.py b/queue_job/__manifest__.py index 1ba6c59940..e997d763c7 100644 --- a/queue_job/__manifest__.py +++ b/queue_job/__manifest__.py @@ -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", diff --git a/queue_job/i18n/de.po b/queue_job/i18n/de.po index 00b450b4b7..ecbcb067da 100644 --- a/queue_job/i18n/de.po +++ b/queue_job/i18n/de.po @@ -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 \n" "Language-Team: none\n" "Language: de\n" @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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!" diff --git a/queue_job/jobrunner/runner.py b/queue_job/jobrunner/runner.py index 5e8d750a01..7f935c63d7 100644 --- a/queue_job/jobrunner/runner.py +++ b/queue_job/jobrunner/runner.py @@ -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). @@ -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 @@ -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( @@ -461,7 +479,8 @@ 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 @@ -469,6 +488,8 @@ def initialize_databases(self): 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(): @@ -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() @@ -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 diff --git a/queue_job/static/description/index.html b/queue_job/static/description/index.html index f585708e59..992e17f4d1 100644 --- a/queue_job/static/description/index.html +++ b/queue_job/static/description/index.html @@ -367,7 +367,7 @@

Job Queue

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:3122e45d99a3e3ce7c38316fbec4714e530da80fd806bcdfff9aa934c4ec0bdb +!! source digest: sha256:71335b8e2973a1871cf0bf504860c2af79d7d15f8c6e39d237f0c396f0b46e9f !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Mature License: LGPL-3 OCA/queue Translate me on Weblate Try me on Runboat

This addon adds an integrated Job Queue to Odoo.