Skip to content
Snippets Groups Projects
Commit ba70c43d authored by Vo Minh Thu's avatar Vo Minh Thu
Browse files

[IMP] inter-process signaling, proof-of-concept.

bzr revid: vmt@openerp.com-20120202173522-2grq11zfm7855i6s
parent e719558c
No related branches found
No related tags found
No related merge requests found
...@@ -17,7 +17,7 @@ pidfile = '.gunicorn.pid' ...@@ -17,7 +17,7 @@ pidfile = '.gunicorn.pid'
# Gunicorn recommends 2-4 x number_of_cpu_cores, but # Gunicorn recommends 2-4 x number_of_cpu_cores, but
# you'll want to vary this a bit to find the best for your # you'll want to vary this a bit to find the best for your
# particular work load. # particular work load.
workers = 4 workers = 1
# Some application-wide initialization is needed. # Some application-wide initialization is needed.
on_starting = openerp.wsgi.on_starting on_starting = openerp.wsgi.on_starting
...@@ -31,6 +31,8 @@ timeout = 240 ...@@ -31,6 +31,8 @@ timeout = 240
max_requests = 2000 max_requests = 2000
#accesslog = '/tmp/blah.txt'
# Equivalent of --load command-line option # Equivalent of --load command-line option
openerp.conf.server_wide_modules = ['web'] openerp.conf.server_wide_modules = ['web']
...@@ -39,7 +41,7 @@ conf = openerp.tools.config ...@@ -39,7 +41,7 @@ conf = openerp.tools.config
# Path to the OpenERP Addons repository (comma-separated for # Path to the OpenERP Addons repository (comma-separated for
# multiple locations) # multiple locations)
conf['addons_path'] = '/home/openerp/addons/trunk,/home/openerp/web/trunk/addons' conf['addons_path'] = '/home/thu/repos/addons/trunk,/home/thu/repos/web/trunk/addons'
# Optional database config if not using local socket # Optional database config if not using local socket
#conf['db_name'] = 'mycompany' #conf['db_name'] = 'mycompany'
......
...@@ -247,7 +247,7 @@ if __name__ == "__main__": ...@@ -247,7 +247,7 @@ if __name__ == "__main__":
# Call any post_load hook. # Call any post_load hook.
info = openerp.modules.module.load_information_from_description_file(m) info = openerp.modules.module.load_information_from_description_file(m)
if info['post_load']: if info['post_load']:
getattr(sys.modules[m], info['post_load'])() getattr(sys.modules['openerp.addons.' + m], info['post_load'])()
except Exception: except Exception:
msg = '' msg = ''
if m == 'web': if m == 'web':
......
...@@ -347,6 +347,14 @@ CREATE TABLE ir_model_data ( ...@@ -347,6 +347,14 @@ CREATE TABLE ir_model_data (
res_id integer, primary key(id) res_id integer, primary key(id)
); );
-- Inter-process signaling:
-- The `base_registry_signaling` sequence indicates the whole registry
-- must be reloaded.
-- The `base_cache_signaling sequence` indicates all caches must be
-- invalidated (i.e. cleared).
CREATE SEQUENCE base_registry_signaling INCREMENT BY 1 START WITH 1;
CREATE SEQUENCE base_cache_signaling INCREMENT BY 1 START WITH 1;
--------------------------------- ---------------------------------
-- Users -- Users
--------------------------------- ---------------------------------
......
...@@ -34,6 +34,8 @@ from openerp.tools.translate import translate ...@@ -34,6 +34,8 @@ from openerp.tools.translate import translate
from openerp.osv.orm import MetaModel, Model, TransientModel, AbstractModel from openerp.osv.orm import MetaModel, Model, TransientModel, AbstractModel
import openerp.exceptions import openerp.exceptions
_logger = logging.getLogger(__name__)
# Deprecated. # Deprecated.
class except_osv(Exception): class except_osv(Exception):
def __init__(self, name, value): def __init__(self, name, value):
...@@ -43,6 +45,14 @@ class except_osv(Exception): ...@@ -43,6 +45,14 @@ class except_osv(Exception):
service = None service = None
# Inter-process signaling:
# The `base_registry_signaling` sequence indicates the whole registry
# must be reloaded.
# The `base_cache_signaling sequence` indicates all caches must be
# invalidated (i.e. cleared).
base_registry_signaling_sequence = None
base_cache_signaling_sequence = None
class object_proxy(object): class object_proxy(object):
def __init__(self): def __init__(self):
self.logger = logging.getLogger('web-services') self.logger = logging.getLogger('web-services')
...@@ -167,6 +177,40 @@ class object_proxy(object): ...@@ -167,6 +177,40 @@ class object_proxy(object):
@check @check
def execute(self, db, uid, obj, method, *args, **kw): def execute(self, db, uid, obj, method, *args, **kw):
# Check if the model registry must be reloaded (e.g. after the
# database has been updated by another process).
cr = pooler.get_db(db).cursor()
registry_reloaded = False
try:
cr.execute('select last_value from base_registry_signaling')
r = cr.fetchone()[0]
global base_registry_signaling_sequence
if base_registry_signaling_sequence != r:
_logger.info("Reloading the model registry after database signaling.")
base_registry_signaling_sequence = r
# Don't run the cron in the Gunicorn worker.
openerp.modules.registry.RegistryManager.new(db, pooljobs=False)
registry_reloaded = True
finally:
cr.close()
# Check if the model caches must be invalidated (e.g. after a write
# occured on another process). Don't clear right after a registry
# has been reload.
cr = pooler.get_db(db).cursor()
try:
cr.execute('select last_value from base_cache_signaling')
r = cr.fetchone()[0]
global base_cache_signaling_sequence
if base_cache_signaling_sequence != r and not registry_reloaded:
_logger.info("Invalidating all model caches after database signaling.")
base_cache_signaling_sequence = r
registry = openerp.modules.registry.RegistryManager.get(db, pooljobs=False)
registry.clear_caches()
finally:
cr.close()
cr = pooler.get_db(db).cursor() cr = pooler.get_db(db).cursor()
try: try:
try: try:
......
...@@ -63,7 +63,7 @@ def start_services(): ...@@ -63,7 +63,7 @@ def start_services():
netrpc_server.init_servers() netrpc_server.init_servers()
# Start the main cron thread. # Start the main cron thread.
openerp.cron.start_master_thread() #openerp.cron.start_master_thread()
# Start the top-level servers threads (normally HTTP, HTTPS, and NETRPC). # Start the top-level servers threads (normally HTTP, HTTPS, and NETRPC).
openerp.netsvc.Server.startAll() openerp.netsvc.Server.startAll()
......
...@@ -421,7 +421,7 @@ def serve(): ...@@ -421,7 +421,7 @@ def serve():
port = config['xmlrpc_port'] port = config['xmlrpc_port']
try: try:
import werkzeug.serving import werkzeug.serving
httpd = werkzeug.serving.make_server(interface, port, application, threaded=True) httpd = werkzeug.serving.make_server(interface, port, application, threaded=False)
logging.getLogger('wsgi').info('HTTP service (werkzeug) running on %s:%s', interface, port) logging.getLogger('wsgi').info('HTTP service (werkzeug) running on %s:%s', interface, port)
except ImportError: except ImportError:
import wsgiref.simple_server import wsgiref.simple_server
...@@ -436,7 +436,7 @@ def start_server(): ...@@ -436,7 +436,7 @@ def start_server():
The WSGI server can be shutdown with stop_server() below. The WSGI server can be shutdown with stop_server() below.
""" """
threading.Thread(target=openerp.wsgi.serve).start() threading.Thread(name='WSGI server', target=openerp.wsgi.serve).start()
def stop_server(): def stop_server():
""" Initiate the shutdown of the WSGI server. """ Initiate the shutdown of the WSGI server.
...@@ -462,11 +462,11 @@ def on_starting(server): ...@@ -462,11 +462,11 @@ def on_starting(server):
openerp.modules.loading.open_openerp_namespace() openerp.modules.loading.open_openerp_namespace()
for m in openerp.conf.server_wide_modules: for m in openerp.conf.server_wide_modules:
try: try:
__import__(m) __import__('openerp.addons.' + m)
# Call any post_load hook. # Call any post_load hook.
info = openerp.modules.module.load_information_from_description_file(m) info = openerp.modules.module.load_information_from_description_file(m)
if info['post_load']: if info['post_load']:
getattr(sys.modules[m], info['post_load'])() getattr(sys.modules['openerp.addons.' + m], info['post_load'])()
except Exception: except Exception:
msg = '' msg = ''
if m == 'web': if m == 'web':
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment