#!/www/python/bin/python # vim: set sts=4 sw=4 et: __revision__ = "$Id: vfab.fcgi,v 1.21 2001/09/12 16:59:31 gward Exp $" import sys from ZODB.POSException import ConflictError from mems.lib import base from quixote.publish import SessionPublisher from quixote import enable_ptl from quixote.http_response import HTTPResponse class VFabPublisher(SessionPublisher): # times to retry a request that failed due to a conflict error CONFLICT_RETRIES = 3 # same as Zope def __init__ (self): SessionPublisher.__init__(self, "mems.ui") # this'll go to Apache's error log self.debug("%s starting up" % sys.argv[0]) # The order of initialization is sensitive and tricky; don't change it # unless you know what you're doing! We read the vfab config file # first in order to find out the location of the quixote logs (debug # and error). Then we set logging, so that any output from later code # goes to the right place (stdout to the debug log, stderr to the error # log). Then we initialize the database, which has to be done before # installing the PTL import hooks (because ZODB's import magic doesn't # work if it comes after import hooks magic -- grumble). Finally, we # fetch the session manager from the database and tell Quixote about # it. self.read_config("/www/conf/vfab.conf") self.setup_logs() base.init_database() enable_ptl() sess_mgr = base.get_session_manager() self.set_session_manager(sess_mgr) # We have to commit the current transaction here, just in case # there wasn't an existing session manager object in the ZODB. # In the case, base.get_session_manager() created a new # session manager and added it to the ZODB root, but then # start_request() will call sync(), losing the modification to # the ZODB root. The net result is that, without the # following commit, the session manager is never written to # disk and sessions are always immediately thrown away. # (This is identical to a comment in portal.fcgi.) get_transaction().commit() def start_request (self, request): base.get_connection().sync() SessionPublisher.start_request(self, request) def format_traversal_error (self, request, exc): from mems.ui.pages import format_traversal_error return format_traversal_error(request, exc) def format_query_error (self, request, exc): from mems.ui.pages import format_query_error return format_query_error(request, exc) def format_access_error (self, request, exc): from mems.ui.pages import format_access_error return format_access_error(request, exc) def format_session_error (self, request, exc): from mems.ui.pages import format_session_error return format_session_error(request, exc) # Don't override format_internal_error. It's possible that PTL templates # don't work. Use the plain old default. def try_publish (self, request, path): """Try to process a single request. Use the base class method to the do actual the work. If a conflict error occurs retry a number of times. """ for i in range(self.CONFLICT_RETRIES + 1): try: return SessionPublisher.try_publish(self, request, path) except ConflictError, exc: oid = exc.args[0] self.debug("ConflictError (%s): retrying request" % `oid`) get_transaction().abort() request.response = HTTPResponse() # reset response object else: raise RuntimeError, "too many conflict errors" def main(): vfab = VFabPublisher() vfab.publish_cgi() #import profile #p = profile.Profile() #p.run('main()') #p.dump_stats('/tmp/profile') if __name__ == '__main__': main()