changeset 32cd371b3e9c in trytond:default
details: https://hg.tryton.org/trytond?cmd=changeset;node=32cd371b3e9c
description:
        Refresh pool of other processes

        When a process change the list of activated modules, the others must 
refresh
        their pool. We do that by just stopping the pool for that database, the 
next
        request will load the new pool.

        issue8988
        review302861002
diffstat:

 CHANGELOG                   |   1 +
 trytond/cache.py            |  31 ++++++++++++++++++++++++++++++-
 trytond/ir/module.py        |   5 ++++-
 trytond/modules/__init__.py |   1 +
 trytond/pool.py             |  16 ++++++++++------
 5 files changed, 46 insertions(+), 8 deletions(-)

diffs (157 lines):

diff -r 9da9d1618bec -r 32cd371b3e9c CHANGELOG
--- a/CHANGELOG Mon Jan 18 23:20:40 2021 +0100
+++ b/CHANGELOG Wed Jan 20 00:52:07 2021 +0100
@@ -1,3 +1,4 @@
+* Refresh pool of other processes
 * Add clear_all method to Cache
 * Support Genshi element directives in HTML editor
 * Add firstline tool
diff -r 9da9d1618bec -r 32cd371b3e9c trytond/cache.py
--- a/trytond/cache.py  Mon Jan 18 23:20:40 2021 +0100
+++ b/trytond/cache.py  Wed Jan 20 00:52:07 2021 +0100
@@ -16,6 +16,7 @@
 
 from trytond import backend
 from trytond.config import config
+from trytond.pool import Pool
 from trytond.transaction import Transaction
 from trytond.tools import resolve, grouped_slice
 
@@ -43,6 +44,15 @@
         return o
 
 
+def _get_modules(cursor):
+    ir_module = Table('ir_module')
+    cursor.execute(*ir_module.select(
+            ir_module.name,
+            where=ir_module.state.in_(
+                ['activated', 'to upgrade', 'to remove'])))
+    return {m for m, in cursor}
+
+
 class BaseCache(object):
     _instances = {}
 
@@ -195,6 +205,7 @@
                 timestamps = {}
                 for timestamp, name in cursor.fetchall():
                     timestamps[name] = timestamp
+                modules = _get_modules(cursor)
         finally:
             database.put_connection(connection)
         for name, timestamp in timestamps.items():
@@ -205,6 +216,7 @@
             inst_timestamp = inst._timestamp.get(dbname)
             if not inst_timestamp or timestamp > inst_timestamp:
                 inst._clear(dbname, timestamp)
+        Pool(dbname).refresh(modules)
         cls._clean_last = datetime.now()
 
     def sync_since(self, value):
@@ -292,6 +304,21 @@
             inst._transaction_lower.pop(dbname, None)
 
     @classmethod
+    def refresh_pool(cls, transaction):
+        database = transaction.database
+        dbname = database.name
+        if not _clear_timeout and database.has_channel():
+            database = backend.Database(dbname)
+            conn = database.get_connection()
+            try:
+                cursor = conn.cursor()
+                cursor.execute(
+                    'NOTIFY "%s", %%s' % cls._channel, ('refresh pool',))
+                conn.commit()
+            finally:
+                database.put_connection(conn)
+
+    @classmethod
     def _listen(cls, dbname):
         database = backend.Database(dbname)
         if not database.has_channel():
@@ -313,7 +340,9 @@
                 conn.poll()
                 while conn.notifies:
                     notification = conn.notifies.pop()
-                    if notification.payload:
+                    if notification.payload == 'refresh pool':
+                        Pool(dbname).refresh(_get_modules(cursor))
+                    elif notification.payload:
                         reset = json.loads(notification.payload)
                         for name in reset:
                             inst = cls._instances[name]
diff -r 9da9d1618bec -r 32cd371b3e9c trytond/ir/module.py
--- a/trytond/ir/module.py      Mon Jan 18 23:20:40 2021 +0100
+++ b/trytond/ir/module.py      Wed Jan 20 00:52:07 2021 +0100
@@ -5,6 +5,7 @@
 
 from sql.operators import NotIn
 
+from trytond.cache import Cache
 from trytond.exceptions import UserError
 from trytond.i18n import gettext
 from trytond.model import ModelView, ModelSQL, fields, Unique, sequence_ordered
@@ -557,7 +558,8 @@
         pool = Pool()
         Module = pool.get('ir.module')
         Lang = pool.get('ir.lang')
-        with Transaction().new_transaction():
+        transaction = Transaction()
+        with transaction.new_transaction():
             modules = Module.search([
                 ('state', 'in', ['to upgrade', 'to remove', 'to activate']),
                 ])
@@ -568,6 +570,7 @@
             lang = [x.code for x in langs]
         if update:
             pool.init(update=update, lang=lang)
+            Cache.refresh_pool(transaction)
         return 'done'
 
 
diff -r 9da9d1618bec -r 32cd371b3e9c trytond/modules/__init__.py
--- a/trytond/modules/__init__.py       Mon Jan 18 23:20:40 2021 +0100
+++ b/trytond/modules/__init__.py       Wed Jan 20 00:52:07 2021 +0100
@@ -302,6 +302,7 @@
 
         # Ensure cache is clear for other instances
         Cache.clear_all()
+        Cache.refresh_pool(transaction)
     logger.info('all modules loaded')
 
 
diff -r 9da9d1618bec -r 32cd371b3e9c trytond/pool.py
--- a/trytond/pool.py   Mon Jan 18 23:20:40 2021 +0100
+++ b/trytond/pool.py   Wed Jan 20 00:52:07 2021 +0100
@@ -113,12 +113,12 @@
         with cls._lock:
             if database_name in cls._instances:
                 del cls._instances[database_name]
-        lock = cls._locks.get(database_name)
-        if not lock:
-            return
-        with lock:
-            if database_name in cls._pool:
-                del cls._pool[database_name]
+            lock = cls._locks.get(database_name)
+            if not lock:
+                return
+            with lock:
+                if database_name in cls._pool:
+                    del cls._pool[database_name]
 
     @classmethod
     def database_list(cls):
@@ -271,6 +271,10 @@
                             cls.__name__, (mixin, cls), {'__slots__': ()})
                         self.add(cls, type=type_)
 
+    def refresh(self, modules):
+        if set(self._modules) != modules:
+            self.stop(self.database_name)
+
 
 def isregisteredby(obj, module, type_='model'):
     pool = Pool()

Reply via email to