Chris McDonough is speculating on a "more perfect app server". Of
course, I'd say that would be a WSGI stack (a-la Paste). But how that works might not be obvious.
I thought I'd speculate on what a "transaction manager" might look
like in this system. I'll just include part of the untested code:
class TransactionManagerMiddleware(object):
def __init__(self, application):
self.application = application
def __call__(self, environ, start_response):
environ['paste.transaction_manager'] = manager = Manager()
# This makes sure nothing else traps unexpected exceptions:
environ['paste.throw_errors'] = True
return wsgilib.catch_errors(application, environ, start_response,
error_callback=manager.error,
ok_callback=manager.finish)
class Manager(object):
def __init__(self):
self.aborted = False
self.transactions = []
def abort(self):
self.aborted = True
def error(self, exc_info):
self.aborted = True
self.finish()
def finish(self):
for trans in self.transactions:
if self.aborted:
trans.rollback()
else:
trans.commit()
And you use it a little like this:
def my_app(environ, start_response):
manager = environ['paste.transaction_manager']
manager.transactions.append(MakeTransactionObject())
...
application = TransactionManagerMiddleware(my_app)
I created the function paste.wsgilib.catch_errors for this, but
only because it's something that's come up before. catch_errors
would be pretty simple if it wasn't for the iterable that applications
can produce.
This is only one of several features Chris mentions, but my point is
one of proof-of-concept -- most of the features he wants can be
implemented separately and in a highly decoupled way using WSGI
middleware (or sometimes simply mundane libraries). The advantages
aren't just testability, but also simplicity (include what you care
about, replace what's broken for you) and the potential for the kind
of distributed development that open source relies on.