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

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

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

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. import subprocess   
  2. #xiaorui.cc   
  3. from subprocess import call   
  4. f=open("/dev/null",'r')   
  5. proc=subprocess.Popen(xxx, shell=True,stdout=f,executable='/bin/bash')   
  6. f.close 

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

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

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

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

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

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

wKioL1OXLQ-RQcz9AAYYBVybewQ020.jpg

他的源码实现方式:

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

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

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

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

责任编辑:林师授 来源: 51CTO博客
相关推荐

2022-05-08 17:53:38

Nacos服务端客户端

2024-01-02 13:58:04

GoREST API语言

2011-09-09 09:44:23

WCF

2010-02-24 15:42:03

WCF服务端安全

2015-11-09 17:51:12

服务器端开发

2016-03-18 09:04:42

swift服务端

2009-08-21 15:54:40

服务端与客户端

2009-08-21 15:36:41

服务端与客户端

2021-03-04 11:37:13

Python服务端urllib

2010-05-28 10:10:49

2009-08-21 14:25:23

C#异步传输字符串

2013-03-25 10:08:44

PHPWeb

2012-03-02 10:38:33

MySQL

2010-03-19 18:17:17

Java Server

2022-10-08 00:01:00

ssrvuereact

2024-01-16 08:05:53

2023-02-22 16:47:09

编程语言RustGolang

2010-08-03 09:59:30

NFS服务

2016-11-03 09:59:38

kotlinjavaspring

2016-08-04 14:41:21

架构java服务端开发
点赞
收藏

51CTO技术栈公众号