且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

用python做服务端时实现守候进程的那些方式

更新时间:2022-10-02 21:48:05

说说,需要做守候进程的时候,我是怎么进化高端的。(怎么高端,具体自己定义,我的土,说不定是你的高端)


python deamon的思路:


1.进程脱离父进程及终端绑定,如果不这样的话,主进程退出,派生的子进程也跟着倒霉了。脱离终端也是这个理。


2.进程唯一性保证,这是废话


3.标准输入/输出/错误重定向,为了不让错误打到前面,又为了更好的分析数据。


说的洋气点、nb点、细化点(其实就os的三个动作):

os.chdir("/")  将当前工作目录更改为根目录。从父进程继承过来的当前工作目录可能在一个装配的文件系统中。

os.setsid() 调用 setsid 以创建一个新对话期,创建了一个独立于当前会话的进程。

os.umask(0) 重设文件创建掩码,子进程会从父进程继承所有权限,可以通过调用这个方法将文件创建掩码初始化成系统默认。



记得最一开始,用的还是shell的手段,nohup 重定向到一个log文件里面。  具体怎么用,我估计大家都懂。

nohup xxxx  xxxx &


紧接着用python的subprocess模块,来fork daemon进程,然后自己退出来。  这样也是实现了守候进程。 subprocess  派生了子进程后,他还是可以有效的控制子进程,比如kill,挂起。

1
2
3
4
5
6
import subprocess
#xiaorui.cc
from subprocess import call
f=open("/dev/null",'r')
proc=subprocess.Popen(xxx, shell=True,stdout=f,executable='/bin/bash')
f.close


学习python的服务端一大利器 twisted的时候,他本身也可以做守候进程的。当然方法有些局限,仅仅适合依照twisted为左右的网络编程。

原文:http://rfyiamcool.blog.51cto.com/1030776/1424809

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/twistd -y
#xiaorui.cc
from twisted.application import service, internet
from twisted.internet import reactor
import time
import os,sys
i=0
def writedata():
    global i
    i+=1
    a=i
    print 'waiting to write data     (%d)'%a
    time.sleep(8)
    print 'writing data!!!!         (%d)'%a
    while True:
        time.sleep(0.2)
        aa=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
        os.system("echo %s >>log"%aa)
 
 
def writeinthread():
    reactor.callInThread(writedata)
 
 
application =service.Application('timeserver')
tservice = internet.TimerService(10000,writeinthread)
tservice.setServiceParent(application )


上面介绍了很多的方法,但是不管是python、golang、ruby社区用supervisor做进程管理的居多。原因,够简单,够直白。  supervisor配置文件是相当的丰富,他还有supervisorctl 终端管理器,更有web 管理界面 。   对我来说,supervisor tornado 绝配。


这段时间找到了一个好模块,pip install daemonize 


这是我写的关于 daemonize demo例子,大家可以直接跑跑。 之后,可以看到,我虽然死循环了,但是后台的服务器还是一直跑着,可以通过进程的状态,或者是通过daemonize本身的函数接口获取状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#xiaorui.cc
from time import sleep
import os,sys
from daemonize import Daemonize
 
pid = "/tmp/test.pid"
 
def wlog():
    f=open('/tmp/nima','a')
    f.write('11')
    f.close()
 
def main():
    while True:
        sleep(5)
        wlog()
 
daemon = Daemonize(app="test_app", pid=pid, action=main)
daemon.start()
daemon.get_pid()
daemon.is_running()

用python做服务端时实现守候进程的那些方式


他的源码实现方式:  

不多说了,就是fork fork fork ....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# Core modules
import atexit
import os
import sys
import time
import signal
 
 
class Daemon(object):
    """
    A generic daemon class.
 
    Usage: subclass the Daemon class and override the run() method
    """
    def __init__(self, pidfile, stdin=os.devnull,
                 stdout=os.devnull, stderr=os.devnull,
                 home_dir='.', umask=022, verbose=1):
        self.stdin = stdin
        self.stdout = stdout
        self.stderr = stderr
        self.pidfile = pidfile
        self.home_dir = home_dir
        self.verbose = verbose
        self.umask = umask
        self.daemon_alive = True
 
    def daemonize(self):
        """
        Do the UNIX double-fork magic, see Stevens' "Advanced
        Programming in the UNIX Environment" for details (ISBN 0201563177)
        http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
        """
        try:
            pid = os.fork()
            if pid > 0:
                # Exit first parent
                sys.exit(0)
        except OSError, e:
            sys.stderr.write(
                "fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
            sys.exit(1)
 
        # Decouple from parent environment
        os.chdir(self.home_dir)
        os.setsid()
        os.umask(self.umask)
 
        # Do second fork
        try:
            pid = os.fork()
            if pid > 0:
                # Exit from second parent
                sys.exit(0)
        except OSError, e:
            sys.stderr.write(
                "fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
            sys.exit(1)
 
        if sys.platform != 'darwin':  # This block breaks on OS X
            # Redirect standard file descriptors
            sys.stdout.flush()
            sys.stderr.flush()
            si = file(self.stdin, 'r')
            so = file(self.stdout, 'a+')
            if self.stderr:
                se = file(self.stderr, 'a+'0)
            else:
                se = so
            os.dup2(si.fileno(), sys.stdin.fileno())
            os.dup2(so.fileno(), sys.stdout.fileno())
            os.dup2(se.fileno(), sys.stderr.fileno())
 
        def sigtermhandler(signum, frame):
            self.daemon_alive = False
            signal.signal(signal.SIGTERM, sigtermhandler)
            signal.signal(signal.SIGINT, sigtermhandler)
 
        if self.verbose >= 1:
            print "Started"
 
        # Write pidfile
        atexit.register(
            self.delpid)  # Make sure pid file is removed if we quit
        pid = str(os.getpid())
        file(self.pidfile, 'w+').write("%s\n" % pid)
 
    def delpid(self):
        os.remove(self.pidfile)
 
    def start(self*args, **kwargs):
        """
        Start the daemon
        """
 
        if self.verbose >= 1:
            print "Starting..."
 
        # Check for a pidfile to see if the daemon already runs
        try:
            pf = file(self.pidfile, 'r')
            pid = int(pf.read().strip())
            pf.close()
        except IOError:
            pid = None
        except SystemExit:
            pid = None
 
        if pid:
            message = "pidfile %s already exists. Is it already running?\n"
            sys.stderr.write(message % self.pidfile)
            sys.exit(1)
 
        # Start the daemon
        self.daemonize()
        self.run(*args, **kwargs)
 
    def stop(self):
        """
        Stop the daemon
        """
 
        if self.verbose >= 1:
            print "Stopping..."
 
        # Get the pid from the pidfile
        pid = self.get_pid()
 
        if not pid:
            message = "pidfile %s does not exist. Not running?\n"
            sys.stderr.write(message % self.pidfile)
 
            # Just to be sure. A ValueError might occur if the PID file is
            # empty but does actually exist
            if os.path.exists(self.pidfile):
                os.remove(self.pidfile)
 
            return  # Not an error in a restart
 
        # Try killing the daemon process
        try:
            = 0
            while 1:
                os.kill(pid, signal.SIGTERM)
                time.sleep(0.1)
                = + 1
                if % 10 == 0:
                    os.kill(pid, signal.SIGHUP)
        except OSError, err:
            err = str(err)
            if err.find("No such process") > 0:
                if os.path.exists(self.pidfile):
                    os.remove(self.pidfile)
            else:
                print str(err)
                sys.exit(1)
 
        if self.verbose >= 1:
            print "Stopped"
 
    def restart(self):
        """
        Restart the daemon
        """
        self.stop()
        self.start()
 
    def get_pid(self):
        try:
            pf = file(self.pidfile, 'r')
            pid = int(pf.read().strip())
            pf.close()
        except IOError:
            pid = None
        except SystemExit:
            pid = None
        return pid
 
    def is_running(self):
        pid = self.get_pid()
        print(pid)
        return pid and os.path.exists('/proc/%d' % pid)
 
    def run(self):
        """
        You should override this method when you subclass Daemon.
        It will be called after the process has been
        daemonized by start() or restart().
        """



使用python做守候进程服务,不知道还有没有更好点、更霸道的方法。大家有的话,要分享下,咱们一块交流下 ....





 本文转自 rfyiamcool 51CTO博客,原文链接:http://blog.51cto.com/rfyiamcool/1424809,如需转载请自行联系原作者