Upstart任务成功完成后挂起

我有一个Upstart任务,启动一个服务的多个实例,基于自动启动多个upstart实例和重新启动实例进程 。 它正在工作,它启动所有的实例,但成功启动后,它只是挂起。 如果我Ctrl-C出来,然后检查具有service status的实例或查看ps他们都成功开始,所以我不知道它挂在什么时候。

这是我的脚本:

 description "all-my-workers" start on runlevel [2345] task 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 

当我做service start all-my-workers我得到这个:

 vagrant@vagrant-service:/etc/init$ sudo service all-my-workers start 

然后它挂在那里,不再提示我。 正如我所说,我可以Ctrl-C出去看看正在运行的工作人员:

 vagrant@vagrant-service:/etc/init$ sudo service all-my-workers status all-my-workers start/running vagrant@vagrant-service:/etc/init$ sudo service my-worker status N=1 my-worker (1) start/running, process 21938 

ps

 worker 21938 0.0 0.1 4392 612 ? Ss 21:46 0:00 /bin/sh -e /proc/self/fd/9 worker 21941 0.2 7.3 174076 27616 ? Sl 21:46 0:00 python /var/lib/my-system/script/start_worker.py 

我不认为这个问题是在my-worker.conf但以防万一:

 description "my-worker" stop on stopping all-my-workers setuid worker setgid worker respawn instance $N console log env SCRIPT_PATH="/var/lib/my-system/script/" script export PROVIDER=vagrant export REGION=all export ENVIRONMENT=cert . /var/lib/my-system/.virtualenvs/my-system/bin/activate python $SCRIPT_PATH/start_worker.py END end script 

谢谢一堆!

我如何解决它?

我假定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答案,显示了这个管理孩子工作的父母工作的想法。 他们展示:

  1. 一个script节的任务
  2. 带有pre-start节的工作

你的父母的工作是一个pre-start节的任务 ,这就是为什么你遇到这种奇怪的行为。

脚本vs预启动

从这个Ask Ubuntu的答案引用这个弃用的文档 ,有两个非常重要的陈述(重点添加):

所有的作业文件都必须有一个exec或script节。 这指定了将要运行的工作。

额外的shell代码可以在exec或script指定的二进制文件或脚本之前之后运行。 这些预计不会开始的过程,事实上,他们不能。 它们是为了准备环境和事后清理。

总之,由Upstart忽略(即不监控)由pre-start节创建的任何后台进程。 相反,您必须使用execscript来产生一个Upstart将监视的进程。

如果你省略了exec / script节,会发生什么? 新贵会坐下来等待一个进程的产生。 因此,你可能写了一个while-true循环:

 script while true; do true done end script 

唯一的区别是while-true循环是一个活锁,而一个空节导致死锁。

工作与任务

了解了上述内容, Upstart任务文档最终引导我们进行下去:

如果没有“任务”关键字, 只要作业开始,导致作业启动的事件将被解除阻止 。 这意味着,这项工作已经发出了一个开始(7)的事件,开始启动前,开始其脚本/执行,后启动,并发出其开始(7)事件。

通过任务, 导致此作业开始的事件将被阻止,直到作业完全转换回停止状态 。 这意味着这个工作已经到达了前面提到的已经开始(7)的事件,并且也完成了它的停止后,排出了已经停止的(7)事件。

(如果你阅读关于启动和停止作业的文档,关于事件和状态的一些细节将更有意义)。

简单地说:

  • 有了普通的Upstart工作, exec / script节会被无限期阻止,因为它启动了一个长期的过程。 因此,Upstart在完成pre-start节之后会停止阻止。
  • 有一项taskexec / script节预计会阻塞一个“有限”的时期,因为它正在启动一个短暂的过程。 因此,Ubstart阻塞,直到exec / script节完成。

但是如果没有exec / script节,会发生什么? 新贵坐在那里无限期地等待着要发起的事情,但这是不会发生的

  • 在工作的情况下,这很好,因为Upstart在等待产卵的过程中不会阻塞,而stop调用显然足以使其停止等待。
  • 然而,在task的情况下,Upstart会永远坐下来,直到你中断为止。 然而,由于还没有找到一个催生的过程,它仍然在技术上运行。 这就是为什么你可以查询中断后的状态,并看到all-my-workers start/running

为了利益的缘故

如果出于某种原因,你真的想把你的父母工作变成一项任务,你实际上需要两个任务:一个是启动my-worker实例,另一个是阻止他们。 您还需要删除stop on stopping all-my-workersmy-worker stop on stopping all-my-workersstop on stopping all-my-workers

开始-所有-我的同事:

 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