首页 > 解决方案 > 轮询比设置多个 setTimeout() 更好

问题描述

我正在开发一个电子邮件提醒系统,以便在任务到期前 24、8、3 和 1 小时 ping 用户。

我有一个在 Node.js 上运行的服务器。我的第一个想法是每次为用户分配任务时设置四个单独的 setTimeout()。但是,我认为在服务器上有数百个 setTimeout() 空闲不会是最好的性能方面。

因此,我是否最好每五分钟轮询一次未完成的任务,并向任务接近截止日期的用户发送提醒?这里的缺点是我会每五分钟读取一次整个 MongoDB 集合。

标签: javascriptnode.jsmongodbsettimeoutpolling

解决方案


Nodejs 非常高效,有很多很多计时器。您可以轻松拥有数以万计的计时器,而不会产生任何有意义的后果。它使用一个排序的链表,插入一个新的计时器只需要很短的时间,并且一旦插入就不会花费任何成本。

只有在列表开始时触发的下一个计时器才会在事件循环中定期进行比较。当它触发时,它会从链表的前面移除,并且链表中的下一个计时器现在位于最前面。因为它是一个链表,所以触发计时器并将其从链表的开头删除的时间与链表的长度无关(例如,它不是一个必须复制下来的数组)。

因此,对于您的特定应用程序,提高数据库效率(尽可能少的请求)远比减少计时器数量重要得多。因此,无论哪种计时器设计/实现可以优化您的数据库负载,我都会推荐。


仅供参考,如果您想提醒用户 4 次关于即将到期的任务,您仍然可以在每个任务的时间只设置一个计时器。将第一个计时器设置为触发,然后当它触发通知时,您对之前保存的到期日期/时间进行一些时间计算,并查看何时设置下一个计时器。这将使您在每个任务中只有一个计时器,而不是四个。

但是,这里的重点仍然是您应该首先优化设计以有效使用数据库。

而且,计时器不是持久的,因此如果您的服务器重新启动,您需要一种机制来在服务器启动时重新创建适当的计时器(可能是一个数据库查询,为您提供在特定时间内挂起的任何任务)。


推荐阅读