I am trying to write an expressjs server utilizing the postgresql as the backend. Each request starts by calling pg.connect
to get a pooled connection (client
) as well as the method to return it to the pool once the connection is no longer needed (done
). For example:
function dbConnect(req, res, next) {
if (res.locals.pgCtx) {
next();
return;
}
pg.connect(dbConn, function (err, client, done) {
if (err) {
res.send(500, err.message);
} else {
app.locals.pgCtx = res.locals.pgCtx = {
client: client,
done: done
};
next();
}
});
}
app.use(allowCrossDomain);
app.use(express.methodOverride());
app.use(express.compress());
app.use(express.bodyParser());
app.use(express.logger());
app.use(passport.initialize());
app.use(express["static"](webRootDir));
app.use(dbConnect); // <--------------
app.use(authenticate);
app.use(app.router);
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
app.set('view engine', 'jade');
app.set('views', webRootDir);
app.engine("jade", jade.__express);
indexHandlers = [fetchConstData, function (req, res) {
res.render(templatesDir + 'index', {
constData: app.locals.constData,
env: app.get('env'),
user: req.user,
admin: isAdmin(req.user.role),
host: req.host
});
}];
app.get('/', indexHandlers);
app.get('/index', indexHandlers);
app.get('/index.html', indexHandlers);
My problem is that while I can insert dbConnect
as the global middleware to be run before any other middleware for a request I also need to be able to cleanup after all the middleware is run in order to return the connection back to the pool.
Ideally, there should be a way to specify a global middleware to be run after all the request specific ones are run regardless of how the request ends - be it by:
res.send(...)
- throwing an exception
- passing err object to
next()
Note, that any request specific middleware can terminate the chain in this way.
Right now I can see only this approach:
- Hook into the negative outcome by registering a custom global error handler middleware instead of
express.errorHandler
. - Replace the
res.send
method in theres
object by a custom version that returns the connection back to pool first and then proceeds to the originalres.send
implementation.
All of this has a strong smell of a hack. I would like to do it right and so I am asking is there a way to register something like a request cleanup middleware?
The static content handler must be moved above the dbConnect
middleware, otherwise we leak db connections until no more connections are available and the server is unable to serve anything because dbConnect
never returns waiting for a connection to be released.