Как это исправить?
Я предполагаю, что my-worker
— это долгоживущий процесс, и вы хотите иметь какой-нибудь простой способ раскрутить и разорвать несколько параллельных экземпляров my-worker
.
Если это так, вы, вероятно, не хотите, чтобы all-my-workers
было task
. Вместо этого вам нужно следующее:
description "all-my-workers"
start on runlevel [2345]
console log
env NUM_INSTANCES=1
env STARTING_PORT=42002
pre-start script
for i in `seq 1 $NUM_INSTANCES`;
do
start my-worker N=$i PORT=$(($STARTING_PORT + $i))
done
end script
pre-stop script
for i in `seq 1 $NUM_INSTANCES`;
do
stop my-worker N=$i PORT=$(($STARTING_PORT + $i)) || true
done
end script
Затем вы можете запустить start all-my-workers
, чтобы запустить все экземпляры my-worker
, а затем запустить stop all-my-workers
, чтобы остановить их. По сути, all-my-workers
становится родительским заданием, которое управляет запуском и остановкой своих дочерних заданий.
Почему?
Вы процитировали два ответа SO, демонстрирующие эту идею родительского задания, управляющего дочерними заданиями. Они показывают:
- задача со строфой
script
- задание со строфой
pre-start
Ваша родительская работа – это задача, состоящая из pre-start
строфы, и именно поэтому вы сталкиваетесь с таким странным поведением.
сценарий против предварительного запуска
Из этого ответа Ask Ubuntu, в котором цитируется эта устаревшая документация содержит два очень важных утверждения (выделение добавлено):
Все файлы заданий должны иметь раздел exec или script. Это указывает, что будет выполняться для задания.
Дополнительный код оболочки может быть задан для запуска до или после двоичного файла или сценария, указанного с помощью exec или сценария. От них не ожидается, что они начнут процесс, на самом деле они не могут этого сделать. Они предназначены для подготовки среды и последующей очистки.
Таким образом, любые фоновые процессы, порожденные разделом pre-start
, игнорируются (т. е. не отслеживаются) Upstart. Вместо этого вы должны использовать exec
или script
, чтобы запустить процесс, за которым будет следить Upstart.
Что произойдет, если вы пропустите строфу exec
/script
? Upstart будет сидеть и ждать запуска процесса. Таким образом, вы могли бы также написать цикл while-true:
script
while true; do
true
done
end script
Единственное отличие состоит в том, что цикл while-true представляет собой активную блокировку, тогда как пустая строфа приводит к взаимоблокировке.
Работа против задач
Зная вышеизложенное, документация Upstart по задачам, наконец, приводит нас к тому, что происходит:
Без ключевого слова «задача» события, вызывающие запуск задания, будут разблокированы, как только задание будет запущено. Это означает, что задание сгенерировало событие start(7), запустило свой предварительный запуск, запустило свой сценарий/исполнение и пост-старт, а также сгенерировало свое событие start(7).
С задачей события, которые приводят к запуску этого задания, будут заблокированы до тех пор, пока задание полностью не перейдет обратно в состояние остановлено. Это означает, что задание дошло до ранее упомянутого события start(7), а также завершило свою пост-остановку и выдало свое событие stop(7).
(Некоторые особенности событий и состояний станут более понятными, если вы прочитаете документацию о запуск и остановка заданий).
Проще говоря:
- Ожидается, что при обычном задании Upstart строфа
exec
/script
будет блокироваться на неопределенный срок, поскольку она запускает долгоживущий процесс. Таким образом, Upstart прекращает блокировку после завершения строфы pre-start
.
- Ожидается, что с
task
строфа exec
/script
будет заблокирована на «конечный» период, потому что она запускает недолговечный процесс. Таким образом, Ubstart блокируется до после завершения строфы exec
/script
.
Но что произойдет, если нет exec
/script
строфы? Upstart сидит и бесконечно ждет, пока что-то будет запущено, но это никогда не произойдет.
- В случае
job
это нормально, потому что Upstart не блокируется в ожидании запуска процесса, а вызова stop
, по-видимому, достаточно, чтобы остановить ожидание.
- Однако в случае с
task
Upstart просто будет сидеть и зависать вечно — или пока вы его не прервете. Однако, поскольку он до сих пор не нашел порожденный процесс, технически он все еще работает. Вот почему вы можете запросить статус после прерывания и увидеть all-my-workers start/running
.
Ради интереса
Если по какой-то причине вы действительно хотите превратить родительское задание в задачу, вам фактически понадобятся две задачи: одна для запуска экземпляров my-worker
и одна для их остановки. Вам также потребуется удалить строфу stop on stopping all-my-workers
из my-worker
.
запустить-все-мои-работники:
description "starts all-my-workers"
start on runlevel [2345]
task
console log
env NUM_INSTANCES=1
env STARTING_PORT=42002
script
for i in `seq 1 $NUM_INSTANCES`;
do
start my-worker N=$i PORT=$(($STARTING_PORT + $i))
done
end script
остановить-все-мои-рабочие:
description "stops all-my-workers"
start on runlevel [!2345]
task
console log
env NUM_INSTANCES=1
env STARTING_PORT=42002
script
for i in `seq 1 $NUM_INSTANCES`;
do
stop my-worker N=$i PORT=$(($STARTING_PORT + $i)) || true
done
end script
person
cyfur01
schedule
30.01.2015