守护进程是生存期长的一种进程。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。他们常常在系统引导装入时启动,在系统关闭时终止。

守护进程的特性

1.在后台运行

2.与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符、控制终端、会话和进程组、工作目录以及文件创建掩码等。这些环境通常是守护进程从执行它的父进程(特别是shell)中继承下来的。

3.启动方式特殊,它可以在系统启动时从启动脚本/etc/rc.d中启动,可以由inetd守护进程启动,可以由crond启动,还可以由用户终端(通常是shell)执行。

总之,除开这些特殊性以外,守护进程与普通进程基本上没有什么区别。因此,编写守护进程实际上是把一个普通进程按照上述的守护进程的特性改造成为守护进程。

守护进程编程规则

1.在后台运行,调用fork ,然后使父进程exit

2.脱离控制终端,登录会话和进程组,调用setsid()使进程成为会话组长

3.禁止进程重新打开控制终端

4.关闭打开的文件描述符,调用fclose()

5.将当前工作目录更改为根目录

6.重设文件创建掩码为0

7.处理SIGCHLD 信号

daemonize Unix系统后台守护进程管理软件

daemonize可以将一个命令运行成Unix的后台。后台程序是不需要借助终端或者登陆的shell运行在服务器上的,并且等待一些时间的出现,或者等待去执行一些规定的任务在一定周期内

Daemonize

选项
1
-a
2
3
挂载到输出文件,而不是冲掉默认值。只有应用了-e and/or -o 被指定的情况。
4
5
-e
6
7
重定向输出标准错误到指定的文件中,替代/dev/null
8
9
-o
10
11
重定向输出标准到指定的文件中,替代/dev/null
12
13
-E name=value
14
15
增加环境变量给给后台程序。这个这个参数类型一定要是name=value格式。可以设置多次。
16
17
-c directory
18
19
指定运⾏路径。
20
21
-p pidfile
22
23
定制自己的pid存放位置。
24
25
-l lockfile
26
27
单实例启动时将会检查这个文件。
28
29
-u user
30
31
定制程序以谁的身份运行的。
32
33
-v
34
35
将会触发daemonize将自己程序的运行详细的日志输出到标准输出中。
安装
1
$ git clone https://github.com/bmc/daemonize.git 
2
$ sh configure && make && sudo make install
使用: Prometheus后台运行
1
$ daemonize -c /data/prometheus/ /data/prometheus/up.sh
2
$ cat  /data/prometheus/up.sh
3
/data/prometheus/prometheus --web.listenaddress="0.0.0.0:9090"        --web.read-timeout=5m    --web.maxconnections=10  --storage.tsdb.retention=15d  --
4
storage.tsdb.path="data/"   --query.max-concurrency=20   --
5
query.timeout=2m

python daemonize

1
$ pip install daemonize

github示例

1
from time import sleep
2
from daemonize import Daemonize
3
4
pid = "/tmp/test.pid"
5
6
7
def main():
8
    while True:
9
        sleep(5)
10
11
daemon = Daemonize(app="test_app", pid=pid, action=main)
12
daemon.start()

参数说明

1
:param app: contains the application name which will be sent to syslog.
2
:param pid: path to the pidfile.
3
:param action: your custom function which will be executed after daemonization.
4
:param keep_fds: optional list of fds which should not be closed.
5
:param auto_close_fds: optional parameter to not close opened fds.
6
:param privileged_action: action that will be executed before drop privileges if user or
7
                          group parameter is provided.
8
                          If you want to transfer anything from privileged_action to action, such as
9
                          opened privileged file descriptor, you should return it from
10
                          privileged_action function and catch it inside action function.
11
:param user: drop privileges to this user if provided.
12
:param group: drop privileges to this group if provided.
13
:param verbose: send debug messages to logger if provided.
14
:param logger: use this logger object instead of creating new one, if provided.
15
:param foreground: stay in foreground; do not fork (for debugging)
16
:param chdir: change working directory if provided or /
使用:
1
from daemonize import Daemonize
2
from time import sleep
3
from datetime import datetime
4
5
pid = "/tmp/test.pid"
6
7
def main(): 主函数, 将业务逻辑放在此处
8
    while True:
9
        sleep(5)
10
        with open('/tmp/test.daemon.log', 'w') as f:
11
            f.write("hello world {}".format(datetime.now()))
12
13
daemon = Daemonize(app="ykyk", pid=pid, action=main)
14
# app 名称可以自定义 syslog中可以查看
15
daemon.start()
1
(python36env) [root@localhost tmp]# ps -ef |grep python
2
root      38408      1  0 10:15 ?        00:00:00 python test_daemon.py
3
            
4
(python36env) [root@localhost tmp]# tail -f test.daemon.log
5
hello world 2019-05-29 10:19:21.743699