Search code examples
node.jsmiddlewarekoakoa2

Execute a middleware one-time only at server startup in Koa v2


I created this middleware which executing only once when any route in the website gets the first hit from a visitor:

// pg-promise
const db = require('./db/pgp').db;
const pgp = require('./db/pgp').pgp;

app.use(async (ctx, next) => {
  try {
    ctx.db = db;
    ctx.pgp = pgp;
  } catch (err) {
    debugErr(`PGP ERROR: ${err.message}` || err);
  }
  await next();
});

// One-Time middleware
// https://github.com/expressjs/express/issues/2457
const oneTime = (fn) => {
  try {
    let done = false;
    const res = (ctx, next) => {
      if (done === false) {
        fn(ctx, next);
        done = true;
      }
      next();
    };
    return res;
  } catch (err) {
    debugErr(`oneTime ERROR: ${err.message}` || err);
  }
};

const oneTimeQuery = async (ctx) => {
  const result = await ctx.db.proc('version', [], a => a.version);
  debugLog(result);
};

app.use(oneTime(oneTimeQuery));

This code executing on the first-time only when a user visiting the website, resulting:

app:log Listening on port 3000 +13ms
app:req GET / 200 - 24ms +2s
23:07:15 connect(postgres@postgres)
23:07:15 SELECT * FROM version()
23:07:15 disconnect(postgres@postgres)
app:log PostgreSQL 9.6.2, compiled by Visual C++ build 1800, 64-bit +125ms

My problem is that I want to execute it at the server start, when there's no any visit on the site.

The future purpose of this code will be to check the existence of tables in the database.

Solution:

Placing this in ./bin/www before the const server = http.createServer(app.callback()); declaration helped:

const query = async () => {
  const db = require('../db/pgp').db;
  const pgp = require('../db/pgp').pgp;
  const result = await db.proc('version', [], a => a.version);
  debugLog(`www: ${result}`);
  pgp.end(); // for immediate app exit, closing the connection pool (synchronous)
};
query();

Solution

  • You could start your application using a js script that requires your app and uses node's native http module to fire up the server. Exactly like in koa-generator (click).

    This is in your app.js file:

    const app = require('koa')();
    ...
    module.exports = app;
    

    And then this is in your script to fire up the server:

    const app = require('./app');
    const http = require('http');
    
    [this is the place where you should run your code before server starts]
    
    const server = http.createServer(app.callback());
    server.listen(port);
    

    Afterwards you start your application with:

    node [script_name].js
    

    Of course keep in mind the async nature of node when doing it this way. What I mean by that - run the 'listen' method on 'server' variable in callback/promise.