Compare commits

..

3 Commits

Author SHA1 Message Date
b5fefffa09 Use a global cached server object for WSGI app
This is instead of caching it inside nilmdb.server.wsgi_application.
Might make things work a bit better in case the web server decides
to call wsgi_application multiple times.
2013-03-30 15:56:57 -04:00
dccb3e370a WSGI config needs to specify application group
This ensures that the same Python sub-instance handles the request,
even if it's coming in from two different virtual hosts.
2013-03-30 15:56:02 -04:00
95ca55aa7e Print out WSGI environment on DB init failure 2013-03-30 15:55:41 -04:00
2 changed files with 20 additions and 9 deletions

View File

@@ -19,8 +19,9 @@ Then, set up Apache with a configuration like:
<VirtualHost> <VirtualHost>
WSGIScriptAlias /nilmdb /home/nilm/nilmdb.wsgi WSGIScriptAlias /nilmdb /home/nilm/nilmdb.wsgi
WSGIProcessGroup nilmdb-server WSGIApplicationGroup nilmdb-appgroup
WSGIDaemonProcess nilmdb-server threads=32 user=nilm group=nilm WSGIProcessGroup nilmdb-procgroup
WSGIDaemonProcess nilmdb-procgroup threads=32 user=nilm group=nilm
# Access control example: # Access control example:
<Location /nilmdb> <Location /nilmdb>

View File

@@ -11,6 +11,7 @@ from nilmdb.utils.time import string_to_timestamp
import cherrypy import cherrypy
import sys import sys
import os import os
import socket
import simplejson as json import simplejson as json
import decorator import decorator
import psutil import psutil
@@ -608,6 +609,11 @@ class Server(object):
def stop(self): def stop(self):
cherrypy.engine.exit() cherrypy.engine.exit()
# Use a single global nilmdb.server.NilmDB and nilmdb.server.Server
# instance since the database can only be opened once. For this to
# work, the web server must use only a single process and single
# Python interpreter. Multiple threads are OK.
_wsgi_server = None
def wsgi_application(dbpath, basepath): # pragma: no cover def wsgi_application(dbpath, basepath): # pragma: no cover
"""Return a WSGI application object with a database at the """Return a WSGI application object with a database at the
specified path. specified path.
@@ -618,29 +624,33 @@ def wsgi_application(dbpath, basepath): # pragma: no cover
is the same as the first argument to Apache's WSGIScriptAlias is the same as the first argument to Apache's WSGIScriptAlias
directive. directive.
""" """
server = [None]
def application(environ, start_response): def application(environ, start_response):
if server[0] is None: global _wsgi_server
if _wsgi_server is None:
# Try to start the server # Try to start the server
try: try:
db = nilmdb.utils.serializer_proxy(nilmdb.server.NilmDB)(dbpath) db = nilmdb.utils.serializer_proxy(nilmdb.server.NilmDB)(dbpath)
server[0] = nilmdb.server.Server( _wsgi_server = nilmdb.server.Server(
db, embedded = True, db, embedded = True,
basepath = basepath.rstrip('/')) basepath = basepath.rstrip('/'))
except Exception: except Exception:
# Build an error message on failure # Build an error message on failure
import pprint
err = sprintf("Initializing database at path '%s' failed:\n\n", err = sprintf("Initializing database at path '%s' failed:\n\n",
dbpath) dbpath)
err += traceback.format_exc() err += traceback.format_exc()
try: try:
import pwd import pwd
import grp import grp
err += sprintf("\nRunning as: uid=%d (%s), gid=%d (%s)\n", err += sprintf("\nRunning as: uid=%d (%s), gid=%d (%s) "
"on host %s, pid %d\n",
os.getuid(), pwd.getpwuid(os.getuid())[0], os.getuid(), pwd.getpwuid(os.getuid())[0],
os.getgid(), grp.getgrgid(os.getgid())[0]) os.getgid(), grp.getgrgid(os.getgid())[0],
socket.gethostname(), os.getpid())
except ImportError: except ImportError:
pass pass
if server[0] is None: err += sprintf("\nEnvironment:\n%s\n", pprint.pformat(environ))
if _wsgi_server is None:
# Serve up the error with our own mini WSGI app. # Serve up the error with our own mini WSGI app.
headers = [ ('Content-type', 'text/plain'), headers = [ ('Content-type', 'text/plain'),
('Content-length', str(len(err))) ] ('Content-length', str(len(err))) ]
@@ -648,5 +658,5 @@ def wsgi_application(dbpath, basepath): # pragma: no cover
return [err] return [err]
# Call the normal application # Call the normal application
return server[0].wsgi_application(environ, start_response) return _wsgi_server.wsgi_application(environ, start_response)
return application return application