【问题标题】:Express: run middleware once per secondExpress:每秒运行一次中间件
【发布时间】:2017-01-22 05:10:01
【问题描述】:

我有一个作为 API 运行的快速服务器,并且我有一个这样加载的中间件:

app.js

const lastActivity = require('./middleware/lastActivity');
app.use(lastActivity);`

中间件/lastActivity.js

module.exports = function(req, res, next) {
    if (req.user && isDifferentDay(req.user.last_activity) {
        User.findById(req.user.id, (err, user) => {
            user.last_activity = Date.now();
            user.save((err) => {
                // also do another async call to an external service, then
                return next();
            }
        });
    }
});

因此,它会检查用户保存的 last_activity 日期是否与今天不同,如果是,则更新用户(我只关心日期,而不关心具体的时间戳)。它还对外部服务进行 API 调用以管理电子邮件营销活动。

但问题是我的网络应用程序在页面加载时同时请求两个资源。这意味着 isDifferentDay 对它们都返回 true,并且用户模型更新了两次,更重要的是,我对速率受限的外部服务进行了两次 API 调用。

一个明显的解决方案是一次只对我的客户执行一个请求,但我真的不想将自己限制在此。我想要的是一种每秒只运行一次中间件的快速“锁”?或者其他我看不到的解决方案。

以 express/node 方式处理此问题的最佳方法是什么?

谢谢。

【问题讨论】:

  • 您对 isDifferentDay 的指定可能是错误的:在同一页面和同一天连续两次调用它不应该都返回 true(除非在 23:59 收到第一个调用: 59 和下一个在 0:00:00)
  • 您在会话中将更新后的last_activity 保存在哪里?我认为如果您在if 条件之后立即更新会话(req.user.last_activity),就可以了。另一件事 - 使用 findByIdAndUpdate 而不是 findById 并保存。更清洁,更快。
  • isDifferentDay 正确返回,因为两个请求同时运行。运行此函数时,它对两者都返回 true,并继续沿该路径前进。
  • 啊,我明白你的意思了@Tom。如果我可以更新会话同步,那应该可以。
  • 你可以。而不是应该工作,它工作:)

标签: node.js express mongoose


【解决方案1】:

这个问题是一个典型的竞争条件。
由于您每天只关心用户的last_activity 一次,而不是使用findById,您可以向数据库请求添加一个额外的过滤器并一次性更新它。 例如

var query = { 
    _id: req.user.id,
    last_activity: req.user.last_activity
};
User.findOneAndUpdate(query, { last_activity: Date.now() }, (err, user) => {
    if (!user)
        return; // user was changed between requests, do nothing
    // ... the rest of your code
});

这样,只有在您的操作之间保持last_activity 不变时,您才会更新用户。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-26
    • 2019-06-06
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    • 2018-12-19
    • 2012-01-09
    • 1970-01-01
    相关资源
    最近更新 更多