Javascript 数据库支持的工作队列

Javascript 数据库支持的工作队列,javascript,architecture,node.js,scale,beanstalkd,Javascript,Architecture,Node.js,Scale,Beanstalkd,我的处境 我有一组工作人员计划定期运行,每个工作人员的时间间隔不同,我希望找到一个好的实现来管理他们的执行 比如说,我有一个工人每周去商店给我买一次牛奶。我想将此作业及其配置存储在mysql表中。但是,轮询表(每秒钟?)并查看哪些作业已准备好放入执行管道似乎是一个真正的坏主意 我所有的工作人员都是用javascript编写的,所以我使用node.js执行并作为管道 如果以异步方式创建新作业(即安排工人在给定时间运行),并且我需要持久存储作业结果和配置,如何避免轮询表 谢谢 我同意这似乎不雅观,但

我的处境

我有一组工作人员计划定期运行,每个工作人员的时间间隔不同,我希望找到一个好的实现来管理他们的执行

比如说,我有一个工人每周去商店给我买一次牛奶。我想将此作业及其配置存储在mysql表中。但是,轮询表(每秒钟?)并查看哪些作业已准备好放入执行管道似乎是一个真正的坏主意

我所有的工作人员都是用javascript编写的,所以我使用node.js执行并作为管道

如果以异步方式创建新作业(即安排工人在给定时间运行),并且我需要持久存储作业结果和配置,如何避免轮询表


谢谢

我同意这似乎不雅观,但考虑到计算机在某处工作的方式,必须进行某种轮询,以确定何时执行哪些作业。那么,让我们来看看你的一些选择:

  • 轮询数据库表。这并不是一个坏主意——如果您将作业存储在MySQL中,这可能是最简单的选择。每秒一次查询的速度算不了什么——尝试一下,你会发现你的系统甚至感觉不到它

    一些想法可以帮助您将其扩展到每秒数百个查询,或者降低系统资源需求:

    • 创建第二个表“job_pending”,将需要在接下来的X秒/分钟/小时内执行的作业放入其中
    • 每隔一段时间仅对包含所有作业的大表运行一次查询,然后每隔一段时间填充查询的小表
    • 从小表中删除已执行的作业以使其保持小
    • 在“执行时间”(或任何你称之为“执行时间”)列上使用索引
  • 如果您需要进一步扩展,请将主jobs表保留在数据库中,并使用第二个较小的表,我建议您将该表放在RAM中:作为DB引擎中的内存表,或者放在程序中的某种队列中。如果有的话,以极短的时间间隔查询队列-这里需要一些极端的用例才能导致任何性能问题

    此选项的主要问题是,您必须跟踪内存中但未执行的作业,例如,由于系统崩溃-您需要更多的编码

  • 为一堆作业中的每一个创建一个线程(比如,下一分钟需要执行的所有作业),并调用thread.sleep(millis_until_execution_time)(或者其他,我对node.js不太熟悉)

    此选项与第2个选项存在相同的问题,在第2个选项中,您必须跟踪作业执行情况以进行崩溃恢复。这也是最浪费的imo——每个睡眠作业线程仍然占用系统资源

  • 当然,可能还有其他选择——我希望其他人能给出更多的答案


    只要意识到每秒轮询数据库一点也不坏。这是imo(记住KISS)中最直接的方法,在这种情况下,您不应该出现性能问题,因此避免过早优化。

    为什么不在node.js中设置一个保存到数据库中的
    作业
    对象呢

    var Job = {
       id: long,
       task: String,
       configuration: JSON,
       dueDate: Date,
       finished: bit
    };
    
    我建议您只将id存储在RAM中,并将所有其他
    作业
    数据保留在数据库中。当超时函数最终运行时,只需知道
    .id
    即可获取其他数据

    var job = createJob(...); // create from async data somewhere.
    job.save(); // save the job.
    var id = job.id // only store the id in RAM
    // ask the job to be run in the future.
    setTimeout(Date.now - job.dueDate, function() {
        // load the job when you want to run it
        db.load(id, function(job) {
            // run it.
            run(job);
            // mark as finished
            job.finished = true;
            // save your finished = true state
            job.save();
        });
    });
    // remove job from RAM now.
    job = null;
    
    如果服务器崩溃,您只需查询具有
    [finished=false]
    的所有作业,将它们加载到RAM中,然后再次启动设置超时

    如果出现任何问题,您应该能够像这样干净地重新启动:

    db.find("job", { finished: false }, function(jobs) {
        each(jobs, function(job) {
             var id = job.id;
             setTimeout(Date.now - job.dueDate, function() {
                 // load the job when you want to run it
                 db.load(id, function(job) {
                     // run it.
                     run(job);
                     // mark as finished
                     job.finished = true;
                     // save your finished = true state
                     job.save();
                 });
             });
             job = null;
        });
    });
    

    我同意KISS说投票没问题。OTOH,通知者/观察者没有任何类型的轮询。当需要发生某些事情时,会通知所有订户。唯一的网络流量是keepalive或心跳,在某些守护进程/系统/软件中,这些流量可以发生得很小。