使用bash&ssh的远程任务队列,用于可变数量的实时工作者

Ste*_*gin 6 parallel-processing ssh bash

我想使用批处理将工作从主服务器分发到多个工作服务器.

理想情况下,我会有一个tasks.txt文件,其中包含要执行的任务列表

cmd args 1
cmd args 2
cmd args 3
cmd args 4
cmd args 5
cmd args 6
cmd args 7
...
cmd args n
Run Code Online (Sandbox Code Playgroud)

并且每个工作服务器将使用ssh进行连接,读取文件并将每一行标记为正在进行或已完成

#cmd args 1  #worker1 - done
#cmd args 2  #worker2 - in progress
#cmd args 3  #worker3 - in progress
#cmd args 4  #worker1 - in progress 
cmd args 5
cmd args 6
cmd args 7
...
cmd args n
Run Code Online (Sandbox Code Playgroud)

我知道如何进行ssh连接,读取文件,远程执行,但不知道如何进行读写原子操作,以免出现2台服务器启动相同任务的情况,以及如何更新这条线.

我希望每个工作人员都能进入任务列表并锁定列表中的下一个可用任务,而不是服务器主动命令工作人员,因为我将根据如何启动或关闭灵活数量的工作克隆我需要完成任务.

更新:

我对工人脚本的想法是:

#!/bin/bash

taskCmd=""
taskLine=0
masterSSH="ssh usr@masterhost"
tasksFile="/path/to/tasks.txt"

function getTask(){
    while [[ $taskCmd == "" ]]
    do
        sleep 1;
        taskCmd_and_taskLine=$($masterSSH "#read_and_lock_next_available_line $tasksFile;")
        taskCmd=${taskCmd_and_taskLine[0]}
        taskLine=${taskCmd_and_taskLine[1]}
    done
}

function updateTask(){
    message=$1
    $masterSSH "#update_currentTask $tasksFile $taskLine $message;"
}


function doTask(){
    return $taskCmd;
}


while [[ 1 -eq 1 ]]
do 
    getTask
    updateTask "in progress"
    doTask 
    taskErrCode=$?
    if [[ $taskErrCode -eq 0 ]]
    then 
        updateTask "done, finished successfully"
    else
        updateTask "done, error $taskErrCode"
    fi
    taskCmd="";
    taskLine=0;

done
Run Code Online (Sandbox Code Playgroud)

Joa*_*ais 2

您可以使用flock并发访问该文件:

exec 200>>/some/any/file ## create a file descriptor
flock -w 30 200 ## concurrently access /some/any/file, timeout of 30 sec.
Run Code Online (Sandbox Code Playgroud)

您可以将文件描述符指向任务列表或任何其他文件,但当然是同一个文件才能工作flock。一旦创建它的进程完成或失败,锁就会被删除。当你不再需要锁时,你也可以自己移除锁:

flock -u 200
Run Code Online (Sandbox Code Playgroud)

使用示例:

ssh user@x.x.x.x '
  set -e
  exec 200>>f
  echo locking...
  flock -w 10 200
  echo working...
  sleep 5
'
Run Code Online (Sandbox Code Playgroud)

set -e如果任何步骤失败,则脚本将失败。玩转sleep时间并并行执行此脚本。sleep一次只会执行一个。