daemon是运行在后台的一种特殊进程。它独立于控制终端并且周期性的执行某种任务或者等待处理某些发生的事件。
从上边定义可以看到:守护进程其实已经脱离了之前的所有环境。所以它很游离,很独立。举个不确定的例子:daemon类似FBI或者克格勃,没人能看到它,但是它却一直在后边做一些事情。
我们最长用daemon来做什么事情呢?我们可以用其来监控一个进程的运行,如果发现其被kill了:那就重新启动它。说白了:用其来守护其他进程。
做法也很简单:首先生成这个守护进程,在这个进程中启动个定时器或者while循环:让其不断检测另外一个进程是否还在运行,如果没有在运行那就启动之。当然:也可以不用检测,直接不断的循环去启动即可! 如果已经正常启动,再次去启动就会失败,这无所谓;如果已经kill,则立即将之启动。
daemon很有意思,守护进程的名字通常以字母'd'结尾
有个很好的例子:lighttpd这个webserver启动后,我们是用其来做服务的,其运行中途忽然挂掉后应该立即重新启动,如果大半夜发生了,码农也不想半夜爬起来去手动重启吧?那为了解决这个问题,最好的办法就是:自动检测到其挂掉,而后自动重新启动!这听着很适合用daemon来做,daemon一直在潜伏的运行,可以用它不断的来检测lighttpd是否在运行,没有就重启。 当然:我们可以自己来实现,事实上也已经有线程的写好的工具了,这就是supervise! 这是daemontools的一个工具.我们用supervise来启动lighttpd的话,其会自动检测lighttpd的运行,如果发现其挂掉了就重新启动!!
事实上:supervise的检测方法也很简单,就是周期性的去启动Lighttpd!!不管是否已经启动,没启动就给启动,启动了也无所谓,不会造成影响。(其启动lighttpd本质上就是用函数execvp()来执行的)
好吧,那如果我们想自己写一个守护进程呢?
那就fork,setsid,fork来创建一个守护进程,而后写个while死循环来不断的调用命令启动某个进程吧···
在写这个daemon的时候推荐创建/写一下pid文件,再daemon被kill时再将这个pid文件给删除!这样后续可以避免启动多个!
=========================================================================================
ok,现在有可daemon,我们可以让其检测确保一个python脚本的执行,这个python脚本可能就是启动某一个服务的。比如启动gunicorn。 好吧,那这里就有两种选择了:一种是用supervise,一种是用Python自己写个daemon。 该用哪种方式呢?我个人推荐用后者,毕竟这样可以方便的搭建环境,同一份代码可以直接拷贝给别人运行,没那么多依赖,不需要它还安装supervise神马的。
当然了,gunicorn可以在配置文件中指定daemon=True来将之搞成一个daemon。
原本我理解成是说:是有个守护进程守护着gunicorn这个进程。 实际不是的,实质上这个选项是说:要不要把gunicorn进程给搞成一个守护进程,其仅仅是一个守护进程,并没有被人守护!! 我们要做的就是:使之被人守护!
所以我们创建一个守护进程来守护gunicorn这个(守护)进程。gunicorn这个进程是一直在运行的,不能挂掉,所以需要被守护!
所以不要理解成:gunicorn配置中daemon=True就是给Gunicorn搞了一个守护进程··就是其被守护!其不会轻易挂掉!可以被自动重启之!!
=========================================================================================
那我还想做一个工作:我们希望更改这个Python程序中的文件后,gunicorn服务会自动重新启动以使之生效!这个就是reloader功能了!
如何实现这个呢?
其实原理也简单:我们要随时检测是否有文件发生了改变(比如比较更改时间),一旦发现其发生了改变,那就直接把gunicorn进程给kill掉, 同时flush这个stdout就可以了。 可能有人要问:你只是kill了,又没有重新启动,其怎么重新跑起来的?哈~别忘记还有守护进程存在呢,其发现Gunicorn被kill了后会直接给重新启动!!
那这个reloader该如何实现呢?
嗯,gunicorn的配置中有一个函数:when_ready(server)
这个函数是在gunicorn服务启动后就会调用运行的函数,在该函数中:我们可以在Gunicorn这个进程中创建一个线程,其写一个死循环,一直检测指定目录的文件变化,发现有变化就直接Kill就ok啦!
嗯,亦即:reloader是在gunicorn进程内部实现的,启动后就开启这个线程来检测文件变化,又就自杀之!
=========================================================================================
一般我们创建这样的程序,一般建立以下几个文件:
①run_gunicorn.py
②gunicorn_server.py
③gunicorn_config.py
④gunicorn_reloader.py
文件gunicorn_reloader.py是封装的reloader线程类,比如类名为reloader,调用reloader.run()就启动这个线程。
在gunicorn_config.py是gunicorn的配置文件,其中要实现when_ready()函数,其实现上就是调用reloader.run()来执行线程
而gunicorn_server.py就是启动gunicorn服务,其会指定配置文件为gunicorn_config.py来启动之!
最后run_gunicorn.py是实现的一个daemon来守护gunicorn服务的(方式就是实现一个daemon,而后循环来执行 python gunicorn_server.py来启动gunicorn服务!!)
那整个流程就串起来了:
我们要做的就是执行python run_gunicorn.py.
其会首先创建一个daemon守护进程,而后循环其执行python gunicorn_server.py
而gunicorn_server.py会启动gunicorn服务进程!!启动是加载gunicorn_config.py这个配置文件中的信息来启动的;同时启动后会创建一个服务进程中的线程来启动reloader,随时检测文件的变化以来kill一下服务!!