我想要一个可以将任意通用脚本或命令转换为守护进程的守护进程.
我想要处理两种常见情况:
我有一个应该永远运行的脚本.如果它死了(或重启),重新启动它.不要让一次运行两个副本(检测副本是否已经在运行并且在这种情况下不启动它).
我有一个简单的脚本或命令行命令,我希望永远重复执行(运行之间的短暂停顿).同样,不要允许一次运行两个脚本副本.
当然,在案例2中围绕脚本编写"while(true)"循环然后为案例1应用解决方案是微不足道的,但更通用的解决方案将直接解决案例2,因为它适用于案例1中的脚本好(你可能只是想更短或没有停顿如果脚本不打算会死(当然,如果剧本真的没有永远不死,则暂停实际上并不重要)).
请注意,解决方案不应涉及将文件锁定代码或PID记录添加到现有脚本中.
更具体地说,我想要一个程序"daemonize",我可以运行
% daemonize myscript arg1 arg2
或者,例如,
% daemonize 'echo `date` >> /tmp/times.txt'
这将保留越来越多的日期列表附加到times.txt.(注意,如果daemonize的参数是一个永远运行的脚本,如上面的情况1那样,那么daemonize仍然会做正确的事情,必要时重新启动它.)然后我可以在我的.login中输入如上所示的命令和/或每小时或每小时一次(取决于我是多么担心它会意外死亡).
注意:daemonize脚本需要记住它正在守护的命令字符串,这样如果再次守护同一个命令字符串,它就不会启动第二个副本.
此外,理想情况下,该解决方案应该适用于OS X和Linux,但欢迎使用其中一种解决方案.
编辑:如果你必须调用它,这很好sudo daemonize myscript myargs
.
(如果我认为这一切都错了,或者有快速和肮脏的局部解决方案,我也很乐意听到.)
PS:如果它有用,这里是一个特定于python的类似问题.
而这个回答类似的问题有什么似乎是一个任意脚本的快速和肮脏的妖魔化一个有用的成语:
您可以使用nohup和&运算符来守护Unix中的任何可执行文件:
nohup yourScript.sh script args&
nohup命令允许您在不杀死脚本的情况下关闭shell会话,而将脚本放在后台,以便获得shell提示继续会话.唯一的小问题是标准输出和标准错误都被发送到./nohup.out,所以如果你在这个庄园中启动几个脚本,他们的输出将交织在一起.更好的命令是:
nohup yourScript.sh script args >script.out 2>script.error&
这会将标准输出发送到您选择的文件和标准错误到您选择的其他文件.如果您只想将一个文件用于标准输出和标准错误,您可以这样做:
nohup yourScript.sh script args >script.out 2>&1 &
2>&1告诉shell将标准错误(文件描述符2)重定向到与标准输出(文件描述符1)相同的文件.
要仅运行一次命令并在它死亡时重新启动它,您可以使用此脚本:
#!/bin/bash if [[ $# < 1 ]]; then echo "Name of pid file not given." exit fi # Get the pid file's name. PIDFILE=$1 shift if [[ $# < 1 ]]; then echo "No command given." exit fi echo "Checking pid in file $PIDFILE." #Check to see if process running. PID=$(cat $PIDFILE 2>/dev/null) if [[ $? = 0 ]]; then ps -p $PID >/dev/null 2>&1 if [[ $? = 0 ]]; then echo "Command $1 already running." exit fi fi # Write our pid to file. echo $$ >$PIDFILE # Get command. COMMAND=$1 shift # Run command until we're killed. while true; do $COMMAND "$@" sleep 10 # if command dies immediately, don't go into un-ctrl-c-able loop done
第一个参数是要使用的pid文件的名称.第二个参数是命令.所有其他参数都是命令的参数.
如果您将此脚本命名为restart.sh,则可以使用以下命令:
nohup restart.sh pidFileName yourScript.sh script args >script.out 2>&1 &
我为长篇答案道歉(请参阅关于我的答案如何指出规范的评论).我正在努力做到全面,所以你尽可能地保持优势.:-)
如果您能够安装程序(具有超级用户权限),并且愿意为执行守护程序执行而设置一次性脚本(即,更简单地指定要在命令行上运行的命令行参数,但是每个服务只需要做一次),我有一种更健壮的方式.
它涉及使用daemontools.本文的其余部分介绍了如何使用daemontools设置服务.
按照如何安装daemontools中的说明进行操作.一些发行版(例如,Debian,Ubuntu)已经有了它的包,所以就这样使用它.
创建一个名为的目录/service
.安装程序应该已经完成此操作,但只是验证或手动安装.如果您不喜欢这个位置,您可以在svscanboot
脚本中更改它,尽管大多数daemontools用户习惯使用/service
,如果您不使用它会感到困惑.
如果您使用的是Ubuntu或其他不使用标准的发行版init
(即不使用/etc/inittab
),则需要使用预安装inittab
作为安排svscanboot
调用的基础init
.这并不难,但您需要知道如何配置init
您的操作系统使用的.
svscanboot
是一个调用的脚本svscan
,它执行寻找服务的主要工作; 它是从所谓init
所以init
会安排如果死以任何理由重新启动它.
每个服务都需要一个服务目录,该目录存储有关服务的内务信息.你也可以建立一个位置来容纳这些服务目录,这样它们就在一个地方; 通常我会使用/var/lib/svscan
,但任何新的位置都可以.
我通常使用脚本来设置服务目录,以节省大量的手动重复性工作.例如,
sudo mkservice -d /var/lib/svscan/some-service-name -l -u user -L loguser "command line here"
这里some-service-name
是你想给你的服务的名称,user
是运行服务为用户,并且loguser
是运行记录仪的用户.(记录稍作解释.)
您的服务必须在前台运行.如果你的程序背景默认,但有一个选项可以禁用它,那么这样做.如果您的程序背景没有办法禁用它,请继续阅读fghack
,虽然这是一个权衡:您无法再使用控制程序svc
.
编辑run
脚本以确保它正在执行您想要的操作.sleep
如果您希望自己的服务经常退出,则可能需要在顶部拨打电话.
如果设置正确,请在/service
指向服务目录时创建符号链接.(不要直接将服务目录放在其中/service
;这使得从svscan
手表中删除服务变得更加困难.)
daemontools日志记录的方式是让服务将日志消息写入标准输出(或标准错误,如果你使用生成的脚本mkservice
); svscan
负责将日志消息发送到日志记录服务.
日志记录服务从标准输入获取日志消息.生成的日志记录服务脚本mkservice
将在log/main
目录中创建自动轮换的带时间戳的日志文件.调用当前日志文件current
.
日志服务可以独立于主服务启动和停止.
通过管道日志文件tai64nlocal
会将时间戳转换为人类可读的格式.(TAI64N是64位原子时间戳,具有纳秒计数.)
使用svstat
得到一个服务的状态.请注意,日志记录服务是独立的,并且具有自己的状态.
您可以使用控制服务(启动,停止,重启等)svc
.例如,要重新启动您的服务,请使用svc -t /service/some-service-name
; -t
意思是"发送SIGTERM
".
其他可用信号包括-h
(SIGHUP
),-a
(SIGALRM
),-1
(SIGUSR1
),-2
(SIGUSR2
)和-k
(SIGKILL
).
要停止服务,请使用-d
.您还可以通过创建down
服务目录中指定的文件来阻止服务在启动时自动启动.
要启动该服务,请使用-u
.这是没有必要的,除非您之前已经将它击倒(或将其设置为不自动启动).
要求主管退出,使用-x
; 通常用于-d
终止服务.这是允许删除服务的常用方法,但您必须首先取消服务链接/service
,否则svscan
将重新启动主管.此外,如果您使用日志服务(mkservice -l
)创建服务,请记住svc -dx /var/lib/svscan/some-service-name/log
在删除服务目录之前也退出日志记录主管(例如).
优点:
daemontools提供了一种创建和管理服务的防弹方法.我将它用于我的服务器,我强烈推荐它.
它的日志系统非常强大,服务自动重启设备也是如此.
因为它使用您编写/调整的shell脚本启动服务,所以您可以根据需要定制服务.
强大的服务控制工具:您可以将大多数信号发送到服务,并可以可靠地上下服务.
您的服务保证是一个干净的执行环境:它们将按照提供的相同环境,进程限制等执行init
.
缺点:
每项服务都需要一些设置.值得庆幸的是,这只需要每次服务一次.
必须将服务设置为在前台运行.此外,为了获得最佳结果,应将它们设置为记录到标准输出/标准错误,而不是syslog或其他文件.
如果您不熟悉daemontools的做事方式,那么陡峭的学习曲线.您必须使用重新启动服务svc
,并且不能直接运行运行脚本(因为它们不会受到主管的控制).
大量的家政文件和大量的家务管理流程.每个服务都需要自己的服务目录,每个服务使用一个管理程序进程在服务死亡时自动重启服务.(如果你有很多的服务,你会看到大量的supervise
在你的进程表的过程.)
总而言之,我认为daemontools是一个满足您需求的出色系统.我欢迎任何有关如何设置和维护它的问题.
你应该看看daemonize.它允许检测第二个副本(但它使用文件锁定机制).它也适用于不同的UNIX和Linux发行版.
如果需要自动启动应用程序作为守护程序,则需要创建适当的init-script.
您可以使用以下模板:
#!/bin/sh # # mydaemon This shell script takes care of starting and stopping # the# # Source function library . /etc/rc.d/init.d/functions # Do preliminary checks here, if any #### START of preliminary checks ######### ##### END of preliminary checks ####### # Handle manual control parameters like start, stop, status, restart, etc. case "$1" in start) # Start daemons. echo -n $"Starting daemon: " echo daemon echo ;; stop) # Stop daemons. echo -n $"Shutting down : " killproc echo # Do clean-up works here like removing pid files from /var/run, etc. ;; status) status ;; restart) $0 stop $0 start ;; *) echo $"Usage: $0 {start|stop|status|restart}" exit 1 esac exit 0
我想你可能想试试start-stop-daemon(8)
./etc/init.d
在任何Linux发行版中查看脚本以获取示例.它可以通过命令行调用或PID文件找到启动的进程,因此它匹配您的所有要求,除了作为脚本的监视程序.但是,您可以随时启动另一个守护程序监视程序脚本,只需在必要时重新启动您的脚本.
作为替代已经提到的daemonize
和daemontools
,有守护进程的libslack包的命令.
daemon
是可配置的,并且关心所有繁琐的守护进程,例如自动重启,日志记录或pidfile处理.
如果你专门使用OS X,我建议你看看launchd是如何工作的.它将自动检查以确保您的脚本正在运行,并在必要时重新启动它.它还包括各种调度功能等.它应满足要求1和2.
至于确保只能运行一个脚本副本,您需要使用PID文件.通常我会将文件写入/var/run/.pid,其中包含当前运行实例的PID.如果文件在程序运行时存在,它会检查文件中的PID是否实际正在运行(程序可能已崩溃或以其他方式忘记删除PID文件).如果是,则中止.如果没有,请开始运行并覆盖PID文件.
Daemontools(http://cr.yp.to/daemontools.html)是由dj bernstein编写的一组非常硬核的实用工具.我已经成功地使用了它.令人讨厌的部分是,当你运行它们时,没有任何脚本返回任何可见的结果 - 只是不可见的返回码.但是一旦它运行它的防弹.