【问题标题】:Job with multiple tasks on different servers在不同服务器上执行多个任务的作业
【发布时间】:2014-08-30 19:58:40
【问题描述】:

我需要一个包含多个任务的作业,在不同的机器上运行,一个接一个(不是同时),当当前作业正在运行时,另一个相同的作业可以到达队列,但不应该启动,直到上一个已经完成。所以我想出了这个“解决方案”,它可能不是最好的,但它可以完成工作:)。我只有一个问题。

我发现我需要一个具有以下结构的 JobQueue(MongoDb 或 Redis):

{
hostname: 'host where to execute the task',
running:FALSE,
task: 'current task number',
tasks:{
    [task_id:1, commands:'run these ecommands', hostname:'aaa'],
    [task_id:2,commands:'another command', hostname:'bbb']
    }
}

主持人:

  • 搜索具有相同主机名的作业,并运行==FALSE
  • 执行在该作业中设置的任务
  • 完成后,主机设置 running=FALSE,检查是否还有其他任务要执行并增加任务编号 + 将主机名设置为下一个任务的下一台计算机

因为作业可以累积,想象一下作业排队等待一台主机的情况:A,B,A

由于我必须运行指定机器的所有作业,我如何不启动第 3 个 A(第一个 A 仍在运行)?

【问题讨论】:

  • 为什么不为每种消息类型设置单独的队列?
  • 消息类型是什么意思?主机名,任务?
  • 它们不都一样吗?从帖子中我了解到您有多个任务,每个任务都在不同的机器上运行,期望有自己的消息类型......
  • 每个任务都在不同的机器上运行,但一次只能运行一个。所以任务 1 用于机器 A 任务 2 仅在机器 A 完成任务后用于机器 B

标签: ruby mongodb redis scheduled-tasks


【解决方案1】:
{
   _id : ObjectId("xxxx"),    // unique, generated by MongoDB, indexed, sortable
   hostname: 'host where to execute the task',
   running:FALSE,
   task: 'current task number',
   tasks:{
      [task_id:1, commands:'run these ecommands', hostname:'aaa'],
      [task_id:2,commands:'another command', hostname:'bbb']
    }
}

问题是下一个可用的“工人”如何知道在特定主机上开始下一个作业是否安全。

您可能需要某种可排序(索引)字段来指示作业的到达顺序。如果您使用的是 MongoDB,那么您可以让它生成 _id,因为它的前四个字节是时间戳,所以它已经是唯一的、索引的和按时间顺序排列的。

您现在可以查询是否有要为特定主机运行的作业,如下所示:

// pseudo code - shell syntax, not actual code
var jobToRun = db.queue.findOne({hostname:<myHostName>},{},{sort:{_id:1}});
if (jobToRun.running == FALSE) {
    myJob = db.queue.findAndModify({query:{_id:jobToRun._id, running:FALSE},update:{$set:{running:TRUE}}});
    if (myJob == null) print("Someone else already grabbed it");
    else {
        /* now we know that we updated this and we can run it */
    }
} else { /* sleep and try again */ }

它的作用是检查特定主机的最早/最早的作业。然后它会查看该作业是否正在运行。如果是,那么什么都不做(睡觉再试一次?)否则尝试通过在_id 上执行 findAndModify 并运行 FALSE 并将 running 设置为 TRUE 来“锁定”它。如果返回该文档,则意味着此过程已成功更新,现在可以开始工作。由于两个线程可能同时尝试执行此操作,如果您返回null,则意味着此文档已更改为由另一个线程运行,我们等待并重新开始。

我建议在某处使用时间戳来指示作业何时开始“运行”,这样如果工人在未完成任务的情况下死亡,则可以“找到”它 - 否则它将“阻止”它后面的所有作业同一主机。

我所描述的适用于队列,在该队列中,您将在作业完成后将其删除,而不是将运行设置回 FALSE - 如果您将运行设置为 FALSE 以便可以完成其他“任务”,那么您可能也会更新任务数组以指示已完成的工作。

【讨论】:

  • 并非如此,running=false 代表 1. 作业未运行并等待启动 2. 作业未运行但在队列中排在第二位,因此在第一个作业完成之前不应启动。它只能找到一项工作,因为应该执行不同的工作。要点是无论当前分配给它的机器都不要执行相同的作业两次
猜你喜欢
  • 1970-01-01
  • 2017-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多