数据库支持的工作队列

我的情况 …

我有一组计划定期运行的工作人员 ,每个工作人员都有不同的时间间隔,并希望find一个良好的实施来pipe理他们的执行。

例如:假设我有一名工人前往商店,每周一次购买我的牛奶。 我想存储这个工作,它的configuration在一个MySQL表中。 但是,轮询表(每秒?)看看哪些作业已经准备好放入执行pipe道似乎是一个非常糟糕的主意。

我的所有工作人员都是用javascript编写的,所以我使用node.js来执行,并将beanstalkd用作stream水线。

如果新创build的作业(即在某个特定时间调度一个工作人员)正在asynchronous创build,并且需要持久地存储作业结果和configuration,我该如何避免轮询表格?

谢谢!

我同意,它似乎不雅,但考虑到计算机的工作方式*某处*将不得不进行某种投票,以便找出要执行的工作时。 所以,让我们来看看你的一些select:

  1. 轮询数据库表。 这根本就不是一个坏主意 – 如果你将作业存储在MySQL中,这可能是最简单的select。 每秒一个查询的速度是没有什么 – 试试看,你会发现你的系统甚至没有感觉到它。

    一些想法可以帮助您将其扩展到每秒可能的数百个查询,或者只是保持系统资源需求:

    • 创build另一个表“job_pending”,在那里你需要在接下来的X秒/分钟/小时内执行这些工作。
    • 在所有工作的大表上只查询一次查询,然后填充查询的小表。
    • 删除从小桌子执行的作业,以保持小。
    • 在你的'execute_time'(或任何你所说的)列上使用一个索引。
  2. 如果你不得不进一步扩展,把主任务表保存在数据库中,然后使用我build议的第二个更小的表,把这个表放在RAM中:或者作为DB引擎中的内存表,或者在某个队列中在你的程序中。 如果您有太多的时间间隔,则会以极短的间隔查询队列 – 这将导致性能问题。

    这个选项的主要问题是,你将不得不跟踪内存中的任务,例如由于系统崩溃而执行的任务 – 为你编写更多的代码…

  3. 为一堆作业(比如说下一分钟需要执行的所有作业)创build一个线程,然后调用thread.sleep(millis_until_execution_time)(或者其他的,我不熟悉node.js)。

    这个选项与没有相同的问题。 2 – 你必须跟踪崩溃恢复的工作执行。 这也是最浪费的imo – 每一个睡眠工作线程仍然需要系统资源。

当然可能有其他的select – 我希望其他人回答更多的想法。

只要意识到每秒轮询数据库根本就不是一个坏主意。 这是最简单的方法(记住KISS),以这个速度你不应该有性能问题,所以要避免过早的优化。

为什么不在node.js中有一个Job对象保存到数据库中。

 var Job = { id: long, task: String, configuration: JSON, dueDate: Date, finished: bit }; 

我build议你只在RAM中存储这个id,并把所有其他的Job数据留在数据库中。 当你的超时函数终于运行时,只需要知道.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中并再次启动setTimeouts。

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

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