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

时间:2022-04-23 01:41:41

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


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,挂起。

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

#!/usr/bin/twistd -y#xiaorui.ccfrom twisted.application import service, internetfrom twisted.internet import reactorimport timeimport os,sysi=0def 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本身的函数接口获取状态。

#xiaorui.ccfrom time import sleepimport os,sysfrom daemonize import Daemonizepid = "/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 ....

# Core modulesimport atexitimport osimport sysimport timeimport signalclass 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:            i = 0            while 1:                os.kill(pid, signal.SIGTERM)                time.sleep(0.1)                i = i + 1                if i % 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做守候进程服务,不知道还有没有更好点、更霸道的方法。大家有的话,要分享下,咱们一块交流下 ....

本文出自 “峰云,就她了。” 博客,谢绝转载!