Reputation: 5605
I am writing some express middleware that needs to access a database. It is going to be released as a package so I want it to be as self contained as possible. I was wondering how I should handle the connection to the database. It is async(of course), but it only needs to happen once when the package is initialized. Where should this happen?
I was thinking something like this. The problems is, the middleware is passed back right away, before the database is ready.
// App
app.use(myMiddleware({
db: "<db connection string>"
});
// Middleware
module.exports = function(db) {
// Open db
return function(req, res, next) {
// Middleware stuff
}
}
Upvotes: 3
Views: 2481
Reputation: 356
use an async function to wrap your create app code and then app.listen after everything is initialized.
// app.js
import express from "express";
export default async () => {
const app = express();
const asyncMiddleware) = await initMWAsync();
app.use(asyncMiddleware);
return app;
}
// entry point of your program
import createApp from "./app";
const server = createApp()
.then(app => app.listen(app.get("port"), () => {
console.log(
" App is running at http://localhost:%d in %s mode",
app.get("port"),
app.get("env")
);
console.log(" Press CTRL-C to stop\n");
}));
export default server;
Upvotes: 0
Reputation: 276306
I'd recommend against such a singleton, dependency injection is a better solution here, and a connection per app is hardly scalable. A connection pool might be a better idea.
That said, you can do something like:
var db = null; // to keep our instance
var asked = false; // to not make several requests that override each other
function openDb(db,ready){
// if we already have it, we return the instance
if(db !== null) ready(null,db);
// if it was already asked by another instance, keep track of it
// to avoid multiple requests.
if(asked) asked.push(ready);
asked = [];
openDbCode(db,function(err,result){
if(err) {
ready(err,null); // error case
asked.forEach(function(fn){ fn(err,null); }); // notify waiters of failure
}
db = result; // save the reference
asked.forEach(function(fn){ fn(db,null); }); // notify all waiters
})
}
This function effectively waits for a db for the first asker and then calls everyone on the same instance. Note that this function will use the first connection string provided.
module.exports = function(db) {
return function(req, res, next) {
openDb(db,function(err,db){
if(err) handleDbOpenErrorLogicHere();
// middleware stuff, same db available here, call next to continue
});
};
}
Upvotes: 2