【问题标题】:Is setTimeout the right option for scheduling tasks spanning days?setTimeout 是跨天安排任务的正确选项吗?
【发布时间】:2020-08-27 04:26:52
【问题描述】:

我正在创建一个用户管理系统。版主可以选择在特定天数内阻止用户。收到阻止请求后,在数据库中将用户的 disabled 属性设置为 true。经过指定的持续时间后,该值将重新设置为 false。持续时间可以从 1 到 10 天不等。 setTimeout() 是正确的选择吗?如果同时为多个用户运行,是否会占用大量 CPU 资源?

这是我程序中的函数。完整程序使用express作为服务器,mongoose与mongodb数据库交互。

function disableUser(req,res) {

    let username = req.body.username;
    let app = req.body.app;
    let duration = req.body.duration;
    let reason = req.body.reason;

    User.find({username:username}).then((result) => {
        let user = result[0];
        user.disabled = true;
        user.save().then((user) => {
            disableMail(app, user.email, duration, reason); //send mail to user
            // schedule a task to set user.disabled to false after the duration
        }, (err) => {
            res.status(500).send(err);
        });
    }, (err) => {
        res.status(500).send(err);
    });

}

编辑: 看到所有的 cmets 和答案,我想我会实现这样的事情:存储禁令的结束日期(使用类似 momentjs 的东西计算)以及 disabled 属性。 setInterval 将单独运行,并每 12 小时检查所有禁用设置为 true 的用户的日期。如果 end_date 与当前日期匹配,则 disabled 属性将设置为 false。

【问题讨论】:

  • 您想要一个持续 1-10 天的 setTimeout 吗?似乎有点过分,而且很可能甚至无法使用您可能拥有的设置。绝对没有必要。发布更多详细信息和一些示例代码。
  • @user120242 我已经添加了有问题的函数。您所说的“甚至无法使用您可能拥有的设置”是什么意思? setTimeout 有使用限制吗?
  • 一个天真的和基本的尝试将代替禁用属性,您将存储日期并使用当前的禁令持续时间延长此日期。此用户将被禁止一段时间。
  • 使用该方法,您可以计算出他们是否被禁止
  • 更好的解决方案是在数据库中存储 bock 状态和天数,并运行一个定时运行的 cron 并监视,如果时间到了,它将恢复任何被阻止用户的状态。跨度>

标签: javascript node.js


【解决方案1】:

由于某些原因,使用 setTimeout 可能不切实际。首先,您是正确的,这将是密集的,特别是如果您有很多被阻止的用户。其次,它不会在服务器重启后存活下来,这可能是因为您正在推送新代码。

如果您使用一些自动化的后台任务,请考虑:

  • 您可能希望检查用户是否在服务器端的所有 API 调用和表单提交中被阻止。这可能是您对写调用的一般安全/权限检查的一部分。
  • 当被禁止用户的 API 调用被拒绝时,您需要在 UI 中进行一些错误处理。
  • 您可能需要一些后台任务,该任务每分钟执行一次并检查被阻止的用户并在适当的时候使禁令到期。 chron 类型的作业或石英(如果是 Java)或类似的东西(如果在 Node 上)可以运行查询并执行更新。

【讨论】:

    【解决方案2】:

    从现在开始设置几天后的setTimeout() 将起作用,并且在服务器上并不困难(即使您有很多),但它可能仍然不是正确的设计选择,原因如下:

    1. setTimeout() 仅在服务器运行期间有效。一旦您的服务器因任何原因(崩溃、计划维护等)重新启动,setTimeout() 就会消失,因此即使您确实使用了setTimeout(),您也必须使用更持久的存储方式这样您就可以在服务器重新启动时恢复所有计时器。

    2. 您不需要ms 计时。多日禁令可以每小时甚至每天取消一次。

    我的建议是,您不要运行计时器,而是运行一些可以每小时运行一次的定期进程,该进程执行查询以查找任何已被禁止过期的被禁止用户。您将希望以一种使查询高效的方式将禁令和禁令持续时间存储在数据库中(可能在一个单独的被禁止用户表中)。然后,您可以每小时运行一次此查询,将用户从被禁止的表中删除,然后为那些已被禁止的用户重新启用“禁用”用户属性。

    这种类型的设计应该满足您的所有目标,是存储禁令的持久方式,并且可以有效地实施。

    【讨论】:

    • 看到所有的 cmets 和答案,我想我会实现这样的东西:存储禁令的结束日期(使用类似 momentjs 的东西计算)以及 disabled 属性。 setTimeout 将单独运行,并每 12 小时检查所有禁用设置为 true 的用户的日期。如果 end_date 与当前日期匹配,则 disabled 属性将设置为 false。
    • @Endemic - 我会检查end_date 是否早于或等于当前日期,以防错过。如果您接触到很多用户,您将不得不评估查询数据库中的所有用户是否足够高效,或者禁用用户表是否是更有效的查询设计。但是,在您接触到很多用户之前不必担心。
    猜你喜欢
    • 2016-11-21
    • 2018-06-20
    • 2017-09-03
    • 2016-09-30
    • 1970-01-01
    • 2015-10-19
    • 2019-11-25
    • 2010-10-04
    相关资源
    最近更新 更多