【问题标题】:Execute a middleware one-time only at server startup in Koa v2在 Koa v2 中,仅在服务器启动时一次性执行中间件
【发布时间】:2017-03-30 21:20:39
【问题描述】:

我创建了这个中间件,它只在网站中的任何路线受到访问者的第一次点击时执行一次:

// 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));

此代码仅在用户首次访问网站时执行,结果:

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

我的问题是我想在服务器启动时执行它,当网站上没有任何访问时。

此代码的未来用途将是检查数据库中是否存在表。

解决方案:

const server = http.createServer(app.callback()); 声明之前将其放在./bin/www 中会有所帮助:

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();

【问题讨论】:

  • pgp.end() 是同步的,它不返回任何内容。
  • 所以我必须在没有await的情况下使用?在我的测试中,无论有没有await,没有pgp.end(),连接池立即关闭的平均请求时间约为100ms,pgp.end()对于多个请求约为7-10ms。我知道它应该像您的示例一样位于 .finally() 承诺块中,但我尝试将您的库与 async/await 一起使用以获得更好的可读性,而不是原生承诺。
  • 你误解了pgp.end的目的。您根本不应该在 HTTP 服务中使用它。目的是关闭整个连接池,只在run-through进程中使用,避免进程退出延迟,就是这样。

标签: node.js middleware koa koa2


【解决方案1】:

您可以使用 js 脚本启动您的应用程序,该脚本需要您的应用程序并使用节点的本机 http 模块来启动服务器。就像在 koa-generator (click) 中一样。

这在您的 app.js 文件中:

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

然后在你的脚本中启动服务器:

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);

然后你开始你的应用程序:

node [script_name].js

这样做时当然要记住节点的异步性质。我的意思是 - 在回调/承诺中的“服务器”变量上运行“监听”方法。

【讨论】:

  • koa-generator 和它有什么关系?
  • 谢谢,成功了!我实际上是使用 koa-generator 启动项目(创建类似于 express-generator 所做的项目结构),但我将我的代码放在 ./bin/www 内的 app.use 中间件中,由于某种原因没有工作。我把我的代码移出这个并放在一个函数中,就像我更新的问题一样。
  • 稍微想了想,app.use 可能没有用,因为在服务器声明之前服务器还没有启动。我知道...
  • @vitaly-t 我认为提供参考可能会有所帮助。 koa-generator(基本上大多数可用的生成器)都在做同样的事情,即将应用程序逻辑(app.js)与启动服务器(bin/www)分开。
猜你喜欢
  • 2021-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-17
  • 2015-10-24
  • 1970-01-01
  • 2017-02-28
  • 2022-11-13
相关资源
最近更新 更多