내가하고 싶은 일은 아주 간단해야합니다. 아래의 솔루션에 도달했습니다. 그것을하는 방법입니다 또는 코드에서 아무것도 리팩터링해야합니다.병렬 프로세스를 생성하고 모든 프로세스가 완료 될 때까지 기다렸다가 다시 실행하십시오.
아래 코드 ... 몇 가지 병렬 프로세스를 만들고이를 다시하고 다시하고 다시 코드를 다시 실행 실행 완료 될 때까지 기다려야한다
스크립트가 한 번 십분에서 cron 작업에 의해 트리거됩니다, 스크립트가 실행 중이면 아무 작업도하지 말고 그렇지 않으면 작업 프로세스를 시작하십시오.
bash 프로그래밍에 익숙하지 않으므로 어떤 통찰력이라도 높이 평가됩니다.
#!/bin/bash
# paths
THISPATH="$(cd "$(dirname "$0")" && pwd)"
# make sure we move in the working directory
cd $THISPATH
# console init path
CONSOLEPATH="$(cd ../../ && pwd)/console.php"
# command line arguments
daemon=0
PHPPATH="/usr/bin/php"
help=0
# flag for binary search
LOOKEDFORPHP=0
# arguments init
while getopts d:p:h: opt; do
case $opt in
d)
daemon=$OPTARG
;;
p)
PHPPATH=$OPTARG
LOOKEDFORPHP=1
;;
h)
help=$OPTARG
;;
esac
done
shift $((OPTIND - 1))
# allow only one process
processesLength=$(ps aux | grep -v "grep" | grep -c $THISPATH/send-campaigns-daemon.sh)
if [ ${processesLength:-0} -gt 2 ]; then
# The process is already running
exit 0
fi
if [ $help -eq 1 ]; then
echo "---------------------------------------------------------------"
echo "| Usage: send-campaigns-daemon.sh |"
echo "| To force PHP CLI binary : |"
echo "| send-campaigns-daemon.sh -p /path/to/php-cli/binary |"
echo "---------------------------------------------------------------"
exit 0
fi
# php executable path, find it if not provided
if [ $PHPPATH ] && [ ! -f $PHPPATH ] && [ $LOOKEDFORPHP -eq 0 ]; then
phpVariants=("php-cli" "php5-cli" "php5" "php")
LOOKEDFORPHP=1
for i in "${phpVariants[@]}"
do
which $i >/dev/null 2>&1
if [ $? -eq 0 ]; then
PHPPATH=$(which $i)
fi
done
fi
if [ ! $PHPPATH ] || [ ! -f $PHPPATH ]; then
# Did not find PHP
exit 1
fi
# load options from app
parallelProcessesPerCampaign=3
campaignsAtOnce=10
subscribersAtOnce=300
sleepTime=30
function loadOptions {
local COMMAND="$PHPPATH $CONSOLEPATH option get_option --name=%s --default=%d"
parallelProcessesPerCampaign=$(printf "$COMMAND" "system.cron.send_campaigns.parallel_processes_per_campaign" 3)
campaignsAtOnce=$(printf "$COMMAND" "system.cron.send_campaigns.campaigns_at_once" 10)
subscribersAtOnce=$(printf "$COMMAND" "system.cron.send_campaigns.subscribers_at_once" 300)
sleepTime=$(printf "$COMMAND" "system.cron.send_campaigns.pause" 30)
parallelProcessesPerCampaign=$($parallelProcessesPerCampaign)
campaignsAtOnce=$($campaignsAtOnce)
subscribersAtOnce=$($subscribersAtOnce)
sleepTime=$($sleepTime)
}
# define the daemon function that will stay in loop
function daemon {
loadOptions
local pids=()
local k=0
local i=0
local COMMAND="$PHPPATH -q $CONSOLEPATH send-campaigns --campaigns_offset=%d --campaigns_limit=%d --subscribers_offset=%d --subscribers_limit=%d --parallel_process_number=%d --parallel_processes_count=%d --usleep=%d --from_daemon=1"
while [ $i -lt $campaignsAtOnce ]
do
while [ $k -lt $parallelProcessesPerCampaign ]
do
parallelProcessNumber=$(($k + 1))
usleep=$(($k * 10 + $i * 10))
CMD=$(printf "$COMMAND" $i 1 $(($subscribersAtOnce * $k)) $subscribersAtOnce $parallelProcessNumber $parallelProcessesPerCampaign $usleep)
$CMD > /dev/null 2>&1 &
pids+=($!)
k=$((k + 1))
done
i=$((i + 1))
done
waitForPids pids
sleep $sleepTime
daemon
}
function daemonize {
$THISPATH/send-campaigns-daemon.sh -d 1 -p $PHPPATH > /dev/null 2>&1 &
}
function waitForPids {
stillRunning=0
for i in "${pids[@]}"
do
if ps -p $i > /dev/null
then
stillRunning=1
break
fi
done
if [ $stillRunning -eq 1 ]; then
sleep 0.5
waitForPids pids
fi
return 0
}
if [ $daemon -eq 1 ]; then
daemon
else
daemonize
fi
exit 0
완전한 해결책을 코딩하려는 기분이 아니므로 몇 가지 코멘트를 드리겠습니다. 'THISPATH' 대신'realpath'를 사용하여 스크립트 자체의 실제 경로를 찾을 수 있는지 확인하십시오. 자신이 시작한 프로세스가 아직 실행 중인지 확인하려면 해당 프로세스에서 열려있는 파일에 대해'fuser'를 시도하십시오. 이는 종종 ps grepping보다 훨씬 쉽습니다. bash가 tail-recursion을 알고 있다고 생각하지 않으므로 waitForPids가 스택 오버플로처럼 보입니다. 그리고 재귀 호출은 리터럴 문자열 pids를 함수로 사용되지 않는 매개 변수로 사용합니다. – Harald
@Harald는 문제를 지적 해 주셔서 감사합니다. 많은 도움이되었습니다. realpath는 내가 아는 한 모든 곳에서 사용할 수 없습니다. 지금까지 프로세스의 단일 인스턴스를 유지하면서 mkdir로 스크립트를 잠그고 트랩을 사용하여 잠금을 해제하기로 결정했습니다. 지금 당장 트릭을하는 것 같다. – Twisted1919
''bash''의'wait' 내장을 고려 했습니까? 네가 원하는 걸 할 수 없어? – janos