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
This commit is contained in:
@@ -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
|
||||
|
||||
+30
-1
@@ -16,6 +16,7 @@ from sql.functions import CurrentTimestamp, Function
|
||||
|
||||
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 @@ def freeze(o):
|
||||
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 @@ class MemoryCache(BaseCache):
|
||||
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 @@ class MemoryCache(BaseCache):
|
||||
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):
|
||||
@@ -291,6 +303,21 @@ class MemoryCache(BaseCache):
|
||||
inst._database_cache.pop(dbname, None)
|
||||
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)
|
||||
@@ -313,7 +340,9 @@ class MemoryCache(BaseCache):
|
||||
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]
|
||||
|
||||
@@ -5,6 +5,7 @@ from functools import wraps
|
||||
|
||||
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 @@ class ModuleActivateUpgrade(Wizard):
|
||||
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 @@ class ModuleActivateUpgrade(Wizard):
|
||||
lang = [x.code for x in langs]
|
||||
if update:
|
||||
pool.init(update=update, lang=lang)
|
||||
Cache.refresh_pool(transaction)
|
||||
return 'done'
|
||||
|
||||
|
||||
|
||||
@@ -302,6 +302,7 @@ def load_module_graph(graph, pool, update=None, lang=None):
|
||||
|
||||
# Ensure cache is clear for other instances
|
||||
Cache.clear_all()
|
||||
Cache.refresh_pool(transaction)
|
||||
logger.info('all modules loaded')
|
||||
|
||||
|
||||
|
||||
+10
-6
@@ -113,12 +113,12 @@ class Pool(object):
|
||||
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 @@ class Pool(object):
|
||||
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()
|
||||
|
||||
Reference in New Issue
Block a user