Прототип скрипта для запуска периодических задач (cron). Понимает 2 типа задач - php и http (расширить думаю не проблема). Пока реализован запуск в блокирующем режиме (т.е. если запустится та же задача при неоконченной предыдущей - она будет отвергнута). Наброски постановки задачи в очередь после существующей - в разработке.
#!/bin/bash
WORK_DIR="$(dirname $(readlink -f $0))"
JOB_TYPE="$1"
JOB_NAME="$2"
# needed by some php jobs
JOB_PARAMS="$3"
SCRIPT_NAME="${0##*/}"
SCRIPT_PID="$$"
# unique job id by his type and path
JOB_ID=($(md5sum <<< "${JOB_TYPE}${JOB_NAME}"))
LOG_DIR='/var/www/log/cronjob'
LOG_FILE="$LOG_DIR/cronjobs"
DELTA_FILE="$LOG_DIR/deltas"
MULTILOCK_FILE="$LOG_DIR/multilocks"
PHP_JOB="/usr/bin/php -f ${JOB_NAME} ${JOB_PARAMS}"
WGET_JOB="/usr/bin/wget -a $LOG_FILE -nv -S --spider ${JOB_NAME}?megaparam=megaid"
LOCK_BASEDIR="$WORK_DIR/locks"
LOCK_DIR="$LOCK_BASEDIR/$JOB_ID"
LOCK_PID="$LOCK_DIR/lock.pid"
QUEUE_FILE="$WORK_DIR/jobs.queue"
NEED_QUEUE=0
QUEUE_POLL=5
PRG_NAME='Yet Another Job Dispatcher'
PRG_VERSION='alpha'
PRG_COPYLEFTS='put_your_cool_nick_here'
check_lock () {
if (( NEED_QUEUE == 1 )); then
if [ -r "$QUEUE_FILE" ]; then
mapfile -t pids < "$QUEUE_FILE"
added=0
for pid in "${pids[@]}"; do [[ $pid = $$ ]] && { added=1; break; }; done
(( added == 0 )) && printf '%s\n' $$ >> "$QUEUE_FILE"
else
printf '%s\n' $$ >> "$QUEUE_FILE"
fi
read -r first < "$QUEUE_FILE" || {
printf '[%s] [%s/%s] An error occurred with the queue system. Exiting.\n' "`date`" $JOB_ID $SCRIPT_PID >> ${LOG_FILE}
exit 1
}
if (( $first == $$ )); then
printf '[%s] [%s/%s] Successfully acquired lock\n' "`date`" $JOB_ID $SCRIPT_PID >> ${LOG_FILE}
trap 'sed -i "/^$$$/d" "$QUEUE_FILE"' 0
else
if kill -0 $first 2>/dev/null; then
sleep "$QUEUE_POLL"
check_lock
else
printf '[%s] [%s/%s] Cleaning queue, %s is not alive\n' "`date`" $JOB_ID $SCRIPT_PID "$first" >> ${LOG_FILE}
sed -i "/^$first$/d" "$QUEUE_FILE"
sleep "$QUEUE_POLL"
check_lock
fi
fi
else
if mkdir "$LOCK_DIR" 2>/dev/null; then
printf '[%s] [%s/%s] Successfully acquired lock\n' "`date`" $JOB_ID $SCRIPT_PID >> ${LOG_FILE}
echo $SCRIPT_PID > $LOCK_PID
return 0
else
printf '[%s] [%s/%s] Cannot acquire lock, giving up on %s\n' "`date`" \
$JOB_ID $SCRIPT_PID "$LOCK_DIR" >> ${LOG_FILE}
printf '[%s] Lock failed for %s\n' "`date`" $JOB_NAME >> ${MULTILOCK_FILE}
return 1
fi
fi
}
remove_lock () {
if [ -d "$LOCK_DIR" ]; then
trap 'rm -rf "$LOCK_DIR"' 0
printf '[%s] [%s/%s] Successfully removed lock\n' "`date`" $JOB_ID $SCRIPT_PID >> ${LOG_FILE}
else
printf '[%s] [%s/%s] WARNING! No lock detected\n' "`date`" $JOB_ID $SCRIPT_PID >> ${LOG_FILE}
printf '[%s] No lock detected for %s\n' "`date`" $JOB_NAME >> ${MULTILOCK_FILE}
fi;
}
if [ "$#" -ge 2 ]; then
#check for existense of base lockdir and create if it's not
if [ ! -d $LOCK_BASEDIR ]; then
mkdir -p $LOCK_BASEDIR;
fi;
case $JOB_TYPE in
"http")
printf '[%s] [%s/%s] Starting HTTP job: %s\n' "`date`" $JOB_ID $SCRIPT_PID $JOB_NAME >> ${LOG_FILE}
if check_lock; then
echo '---JOB OUTPUT---' >> ${LOG_FILE}
START_TIME=$(date +%s.%N)
${WGET_JOB}
END_TIME=$(date +%s.%N)
DELTA_TIME=$(echo "$END_TIME - $START_TIME"|bc )
echo '---END OF JOB OUTPUT---' >> ${LOG_FILE}
printf '[%s] [%s/%s] HTTP job done (%.3F sec): %s\n' "`date`" $JOB_ID $SCRIPT_PID $DELTA_TIME $JOB_NAME >> $LOG_FILE
printf '[%s] %.3F sec for job %s\n' "`date`" $DELTA_TIME $JOB_NAME >> ${DELTA_FILE}
remove_lock
fi;
;;
"php")
printf '[%s] [%s/%s] Starting PHP job: %s\n' "`date`" $JOB_ID $SCRIPT_PID $JOB_NAME >> ${LOG_FILE}
if check_lock; then
echo '---JOB OUTPUT---' >> ${LOG_FILE}
START_TIME=$(date +%s.%N)
${PHP_JOB} 2>> ${LOG_FILE}
END_TIME=$(date +%s.%N)
DELTA_TIME=$(echo "$END_TIME - $START_TIME"|bc )
echo '---END OF JOB OUTPUT---' >> ${LOG_FILE}
printf '[%s] [%s/%s] PHP job done (%.3F sec): %s\n' "`date`" $JOB_ID $SCRIPT_PID $DELTA_TIME $JOB_NAME >> $LOG_FILE
printf '[%s] %.3F sec for job %s\n' "`date`" $DELTA_TIME $JOB_NAME >> ${DELTA_FILE}
remove_lock
fi;
;;
esac
else
echo "Usage: $SCRIPT_NAME <JOB_TYPE> <JOB_NAME>"
echo 'Run HTTP or PHP job with lock. Usually called by cron'
echo ' <JOB_TYPE> is [http|php]'
echo ' <JOB_NAME> is URL (if http) or path to php-script (if php)'
echo "$PRG_NAME $PRG_VERSION (all copylefts belongs to $PRG_COPYLEFTS)"
fi
Лог LOG_FILE содержит всё, DELTA_FILE - времена затраченные на выполнение задач и MULTILOCK_FILE -задачи, запуск которых был блокирован как повторных (конкурентных). По-умолчанию, в папке со скриптом создаётся папка locks - в ней будут появляться папки-локи для задач. Т.е. нужны права на запись пользователю от которого будет запущен этот скрипт.
Блокировка созданием папок, как я понял - пока единственный адекватно работающий на всём чем только можно способ атомизировать создание лока =) Основная идея подчерпнута отсюда.
Не смущайтесь слова диспетчер (dispatcher), так как это всего лишь менеджер (manager), просто звучит круто =)
Не смущайтесь слова диспетчер (dispatcher), так как это всего лишь менеджер (manager), просто звучит круто =)
Друг, у тебя отличный блог в плане контента, но вот
ОтветитьУдалитьбекграунд - взрыв мозга. Можно убрать это эхо спектрума?
как же, весь шарм исчезнет =)
УдалитьКак с вами можно связаться есть у вас icq или скайп ?
ОтветитьУдалитьзаведите аккаунт в Google, тогда сможете оставлять сообщения приватно
ОтветитьУдалитьICQ не пользуюсь лет 6 как, Skype очень редко