details:   https://code.tryton.org/tryton/commit/cb5c6667ac51
branch:    default
user:      Cédric Krier <[email protected]>
date:      Tue May 19 12:29:44 2026 +0200
description:
        Support pool process with spawn context for cron and worker

        When max_tasks_per_child is set, the ProcessPoolExecutor uses a spawn
        multiprocessing context which starts a new process from scratch with a 
__name__
        being __mp_main__ which prevents the configuration to be restored.
        So in the ProcessPoolExecutor initializer the configuration is restored 
using
        the initial options.

        Closes #14843
diffstat:

 trytond/bin/trytond-cron   |   4 +++-
 trytond/bin/trytond-worker |   4 +++-
 trytond/trytond/cron.py    |  11 ++++++++---
 trytond/trytond/worker.py  |  15 +++++++++++----
 4 files changed, 25 insertions(+), 9 deletions(-)

diffs (125 lines):

diff -r 7e5197d5a61c -r cb5c6667ac51 trytond/bin/trytond-cron
--- a/trytond/bin/trytond-cron  Thu May 21 10:26:44 2026 +0200
+++ b/trytond/bin/trytond-cron  Tue May 19 12:29:44 2026 +0200
@@ -13,4 +13,6 @@
 
 from trytond.cli.cron import main  # noqa: E402
 
-main()
+# Ensure main module can be safely imported by a new interpreter
+if __name__ == '__main__':
+    main()
diff -r 7e5197d5a61c -r cb5c6667ac51 trytond/bin/trytond-worker
--- a/trytond/bin/trytond-worker        Thu May 21 10:26:44 2026 +0200
+++ b/trytond/bin/trytond-worker        Tue May 19 12:29:44 2026 +0200
@@ -12,4 +12,6 @@
 
 from trytond.cli.worker import main  # noqa: E402
 
-main()
+# Ensure main module can be safely imported by a new interpreter
+if __name__ == '__main__':
+    main()
diff -r 7e5197d5a61c -r cb5c6667ac51 trytond/trytond/cron.py
--- a/trytond/trytond/cron.py   Thu May 21 10:26:44 2026 +0200
+++ b/trytond/trytond/cron.py   Tue May 19 12:29:44 2026 +0200
@@ -8,6 +8,8 @@
 from concurrent import futures
 from multiprocessing import cpu_count
 
+import trytond.commandline as commandline
+import trytond.config as config
 from trytond.pool import Pool
 from trytond.transaction import Transaction
 
@@ -25,7 +27,7 @@
         max_workers=processes,
         mp_context=None,
         initializer=initializer,
-        initargs=(options.database_names,),
+        initargs=(options,),
         max_tasks_per_child=options.maxtasksperchild or None,
         )
     if sys.version_info < (3, 11):
@@ -42,12 +44,15 @@
                 time.sleep(60 - (now.second + now.microsecond / 10**6))
 
 
-def initializer(database_names, worker=True):
+def initializer(options, worker=True):
+    # restore configuration when mp context is spawn
+    config.update_etc(options.configfile)
+    commandline.config_log(options)
     if worker:
         signal.signal(signal.SIGINT, signal.SIG_IGN)
     pools = []
     database_list = Pool.database_list()
-    for database_name in database_names:
+    for database_name in options.database_names:
         pool = Pool(database_name)
         if database_name not in database_list:
             with Transaction().start(database_name, 0, readonly=True):
diff -r 7e5197d5a61c -r cb5c6667ac51 trytond/trytond/worker.py
--- a/trytond/trytond/worker.py Thu May 21 10:26:44 2026 +0200
+++ b/trytond/trytond/worker.py Tue May 19 12:29:44 2026 +0200
@@ -12,7 +12,8 @@
 
 from sql import Flavor
 
-from trytond import backend, config
+import trytond.commandline as commandline
+import trytond.config as config
 from trytond.exceptions import UserError, UserWarning
 from trytond.pool import Pool
 from trytond.status import processing
@@ -24,6 +25,7 @@
 
 class Queue(object):
     def __init__(self, database_name, executor):
+        from trytond import backend
         self.database = backend.Database(database_name).connect()
         self.connection = self.database.get_connection(autocommit=True)
         self.executor = executor
@@ -57,6 +59,7 @@
 
 
 def work(options):
+    from trytond import backend
     Flavor.set(backend.Database.flavor)
     if not config.getboolean('queue', 'worker', default=False):
         return
@@ -69,7 +72,7 @@
         max_workers=processes,
         mp_context=None,
         initializer=initializer,
-        initargs=(options.database_names,),
+        initargs=(options,),
         max_tasks_per_child=options.maxtasksperchild or None,
         )
     if sys.version_info < (3, 11):
@@ -112,12 +115,15 @@
                     queue.get_notifications()
 
 
-def initializer(database_names, worker=True):
+def initializer(options, worker=True):
+    # restore configuration when mp context is spawn
+    config.update_etc(options.configfile)
+    commandline.config_log(options)
     if worker:
         signal.signal(signal.SIGINT, signal.SIG_IGN)
     pools = []
     database_list = Pool.database_list()
-    for database_name in database_names:
+    for database_name in options.database_names:
         pool = Pool(database_name)
         if database_name not in database_list:
             with Transaction().start(database_name, 0, readonly=True):
@@ -127,6 +133,7 @@
 
 
 def run_task(pool, task_id):
+    from trytond import backend
     if not isinstance(pool, Pool):
         database_list = Pool.database_list()
         pool = Pool(pool)

Reply via email to