Python example five Python daemon and script singleton run

Source: Internet
Author: User

First, Introduction

The most important feature of the daemon is running in the background, which must be isolated from the environment before it is run, including non-closed file descriptors, control terminals, session and process groups, working directories, and file creation masks, and so on, which can be/etc/from startup scripts at system startup RC.D, which can be started by the inetd daemon, can be started by the job planning process Crond, and can be executed by the user terminal (usually the shell).
Python sometimes needs to ensure that only one instance of a script is run to avoid data conflicts.

Second, the Python daemon
1. Function Implementation
#!/usr/bin/env python#coding:utf-8import sys, OS ' fork the current process into a daemon note: If your daemon is initiated by inetd, do not do so! INETD has done all the things that need to be done, including redirecting standard file descriptors, the only thing that needs to be done is chdir () and Umask () "Def daemonize (stdin= '/dev/null ', stdout= '/dev/null ', Stderr= '/dev/null '): #重定向标准文件描述符 (directed to/dev/null by default) Try:pid = Os.fork () #父进程 (conversation group leader process) exits, which means a non-        The conversation group leader process can never regain control of the terminal.  If PID > 0:sys.exit (0) #父进程退出 except OSError, E:sys.stderr.write ("Fork #1 failed: (%d)%s\n" % (E.errno, e.strerror)) Sys.exit (1) #从母体环境脱离 Os.chdir ("/") #chdir确认进程不保持任何目录于使用状态, otherwise you cannot umount a file system.    It can also be changed to the directory that is important for the daemon to run Os.umask (0) #调用umask (0) in order to have complete control over anything written, because sometimes it is not known what kind of umask to inherit.     Os.setsid () #setsid调用成功后, the process becomes the new session leader and the new process leader, and is detached from the original logon session and process group.          #执行第二次fork try:pid = os.fork () if PID > 0:sys.exit (0) #第二个父进程退出 except OSError, E: Sys.stderr.write ("Fork #2 failed: (%d)%s\n"% (E.errno, e.strerror)) Sys.exit (1) #进程已经是守护进程了, redirect standard file descriptor for F in Sys.stdout, Sys.stderr:f.flush () si = open (stdin, ' r ') so = open (stdout, ' A + ') se = open (stderr, ' A + ', 0) os.dup2 (Si.fileno (), Sys.stdin.fileno ()) #dup2函数原子化关闭和复制文件描述符 os.dup2 (So.fileno (), SYS.STDOUT.F Ileno ()) os.dup2 (Se.fileno ()), Sys.stderr.fileno ()) #示例函数: Prints a number and timestamp per second def main (): Import time Sys.stdout.write (' Dae  Mon started with PID%d\n '% os.getpid ()) sys.stdout.write (' Daemon stdout output\n ') sys.stderr.write (' Daemon stderr        Output\n ') c = 0 while True:sys.stdout.write ('%d:%s\n '% (c, time.ctime ())) Sys.stdout.flush () c = c+1 Time.sleep (1) if __name__ = = "__main__": daemonize ('/dev/null ', '/tmp/daemon_stdout.log ', '/tmp/daemon_ Error.log ') Main ()
can be ps-ef by command | grep daemon.py views the inheritance running in the background,/tmp/daemon_error.log logs the error run log, and the standard output log is logged in/tmp/daemon_stdout.log.

2. Class implementation
#!/usr/bin/env Python#coding:utf-8#python simulation linux daemon import sys, OS, time, atexit, Stringfrom signal Import Sigtermclass daemon:def __init__ (self, pidfile, stdin= '/dev/null ', stdout= '/dev/null ', stderr= '/dev/null '): #需要获取调试    Information, change to stdin= '/dev/stdin ', stdout= '/dev/stdout ', stderr= '/dev/stderr ', run as root. Self.stdin = stdin Self.stdout = stdout Self.stderr = stderr self.pidfile = Pidfile def _daemonize (self): t      Ry:pid = Os.fork () #第一次fork, generating child processes, leaving parent process if PID > 0:sys.exit (0) #退出主进程 except OSError, E: Sys.stderr.write (' fork #1 failed:%d (%s) \ n '% (E.errno, e.strerror)) Sys.exit (1) os.chdir ("/") #修改工作目      Record Os.setsid () #设置新的会话连接 os.umask (0) #重新设置文件创建权限 try:pid = Os.fork () #第二次fork, prevents the process from opening the terminal If PID > 0:sys.exit (0) except OSError, E:sys.stderr.write (' fork #2 failed:%d (%s) \ n '% (E.errno, e.st Rerror)) Sys.exit (1) #重定向文件描述符 Sys.stdout.flush () sys.stderr. Flush () si = file (Self.stdin, ' r ') so = File (Self.stdout, ' A + ') se = file (self.stderr, ' A + ', 0) os.dup2 (si.fi       Leno (), Sys.stdin.fileno ()) os.dup2 (So.fileno (), Sys.stdout.fileno ()) os.dup2 (Se.fileno (), Sys.stderr.fileno ()) #注册退出函数, depending on the file PID, determine if there is a process atexit.register (self.delpid) pid = str (os.getpid ()) file (Self.pidfile, ' w+ '). Write ('%s\n '% pid ' def delpid (self): Os.remove (Self.pidfile) def start (self): #检查pid文件是否存在以探测是否存在进程 TRY:PF = fil      E (self.pidfile, ' r ') pid = Int (Pf.read (). Strip ()) Pf.close () except ioerror:pid = None if pid: Message = ' Pidfile%s already exist. Daemon already running!\n ' sys.stderr.write (message% self.pidfile) sys.exit (1) #启动监控 self._daemonize ( ) Self._run () def stop (self): #从pid文件中获取pid try:pf = File (self.pidfile, ' r ') pid = Int (Pf.read (). Strip ()) Pf.close () except ioerror:pid = None if not pid: #重启不报错 message = ' Pidfile%s 'does not exist. Daemon not running!\n ' sys.stderr.write (message% self.pidfile) return #杀进程 try:while 1:os. Kill (PID, SIGTERM) Time.sleep (0.1) #os. System (' hadoop-daemon.sh stop Datanode ') #os. System (' Hadoop-da emon.sh Stop Tasktracker ') #os. Remove (self.pidfile) except OSError, Err:err = str (ERR) if Err.find (' N o such process ') > 0:if os.path.exists (self.pidfile): Os.remove (self.pidfile) else:print    STR (ERR) sys.exit (1) def restart (self): Self.stop () Self.start () def _run (self): "" "Run Your Fun" "" While True: #fp =open ('/tmp/result ', ' A + ') #fp. Write (' Hello world\n ') sys.stdout.write ('%s:hello world\n '% ( Time.ctime (),) Sys.stdout.flush () Time.sleep (2) if __name__ = = ' __main__ ': daemon = Daemon ('/tmp/watch_p Rocess.pid ', stdout = '/tmp/watch_stdout.log ') If Len (sys.argv) = = 2:if ' start ' = = Sys.argv[1]: Daem On.start() elif ' stop ' = = Sys.argv[1]: daemon.stop () elif ' restart ' = = Sys.argv[1]: daemon.res Tart () else:print ' Unknown Command ' sys.exit (2) sys.exit (0) Else:print ' Us Age:%s Start|stop|restart '% sys.argv[0] Sys.exit (2)
Operation Result:

can refer to : http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/, it is when Daemon is designed into a template , in other files from daemon import daemon, and then define subclasses, overriding the Run () method to implement its own functionality.

Class Mydaemon (Daemon):    def run (self):        while True:            fp=open ('/tmp/run.log ', ' A + ')            fp.write (' Hello world\n ')            time.sleep (1)
Insufficient: Signal processing signal.signal (signal. SIGTERM, Cleanup_handler) is not installed temporarily, the callback function Delpid () is not called when the registration program exits.
Then, write a shell command, join the start-up service, every 2 seconds to detect whether the daemon is started, if not started, automatically monitor the recovery program.
#/bin/shwhile Truedo  count= ' ps-ef | grep "daemonclass.py" | grep-v "grep" '  if ["$?"! = "0"]; then     DAEMONCL ass.py start  fi  sleep 2done
third, Python guarantees that only one script instance can be run
1. Open the file itself and lock
#!/usr/bin/env python#coding:utf-8import fcntl, sys, time, ospidfile = 0def applicationinstance ():    Global pidfile< C1/>pidfile = open (Os.path.realpath (__file__), "R")    try:        fcntl.flock (Pidfile, Fcntl. LOCK_EX | Fcntl. LOCK_NB) #创建一个排他锁 and locked other processes will not block    except:        print "another instance is running ..."        sys.exit (1) if __name__ = = "__main__":    applicationinstance () while    True:        print ' running ... '        time.sleep (1)
Note: The open () parameter cannot use W, otherwise it overwrites itself; The pidfile must be declared as a global variable, otherwise the local variable life cycle ends, and the file descriptor is reclaimed by the system because the reference count is 0 (if the entire function is written in the main function, it does not need to be defined as global).

2. Open the customization file and lock it
#!/usr/bin/env python#coding:utf-8import fcntl, sys, timepidfile = 0def applicationinstance ():    Global Pidfile    Pidfile = open ("Instance.pid", "W")    try:        fcntl.lockf (Pidfile, Fcntl. LOCK_EX | Fcntl. LOCK_NB)  #创建一个排他锁 and locked other processes will not block    except  IOError:        print "another instance is running ..."        Sys.exit (0) If __name__ = = "__main__":    applicationinstance () while    True:        print ' running ... '        Time.sleep (1)
3, the detection file PID
#!/usr/bin/env python#coding:utf-8import time, OS, sysimport signalpidfile = '/tmp/process.pid ' def sig_handler (SIG, FRAME):    if Os.path.exists (pidfile):        os.remove (pidfile)    sys.exit (0) def applicationinstance ():    Signal.signal (signal. SIGTERM, Sig_handler)    signal.signal (signal. SIGINT, Sig_handler)    signal.signal (signal. Sigquit, Sig_handler)    try:      pf = file (pidfile, ' R ')      pid = Int (Pf.read (). Strip ())      pf.close ()    Except IOError:      pid = None      if pid:      sys.stdout.write (' instance is running...\n ')      sys.exit (0)    file (pidfile, ' w+ '). Write ('%s\n '% os.getpid ()) If __name__ = = "__main__":    ApplicationInstance () while    True:        print ' running ... '        time.sleep (1)

4. Detecting specific folders or files
#!/usr/bin/env python#coding:utf-8import time, commands, signal, Sysdef Sig_handler (SIG, frame):    if os.path.exists ("/tmp/test"):        os.rmdir ("/tmp/test")    sys.exit (0) def applicationinstance ():    signal.signal (signal. SIGTERM, Sig_handler)    signal.signal (signal. SIGINT, Sig_handler)    signal.signal (signal. Sigquit, Sig_handler)    if Commands.getstatusoutput ("Mkdir/tmp/test") [0]:        print "instance is running ..."        Sys.exit (0) If __name__ = = "__main__":    applicationinstance () while    True:        print ' running ... '        Time.sleep (1)

You can also detect a specific file to determine if the file exists:

Import Osimport os.pathimport time #class used to handle one application instance Mechanismclass applicationinstance: #sp Ecify the file used to save the application instance Piddef __init__ (self, pid_file): Self.pid_file = Pid_fileself.check ( ) self.startapplication () #check If the current application is already runningdef check (self): #check if the pidfile exist Sif not Os.path.isfile (self.pid_file): Return #read the pid from the Filepid = 0try:file = Open (Self.pid_file, ' RT ') dat A = File.read () file.close () pid = int (data) Except:pass#check if the process with specified by pid existsif 0 = = Pid:retur n Try:os.kill (PID, 0) #this would raise an exception if the PID is not Validexcept:return #exit the Applicationprint "the Application is already running ... "exit (0) #exit raise an exception so don ' t put it in a try/except block #called when the Single instance starts to save it's piddef startapplication (self): File = open (self.pid_file, ' wt ') file.write (str (OS). Getpid ())) File.close () #called when the "instance exit" (remove PID file) def exitapplication (self): Try:os.remove (self.pid_file) except :p if __name__ = = ' __main__ ': #create application instanceappinstance = applicationinstance ('/tmp/myapp.pid ') #do som Ething hereprint "Start MyApp" Time.sleep (5) #sleep 5 secondsprint "End myapp" #remove pid fileappinstance.exitapplication ()
The above Os.kill (PID, 0) is used to detect whether a process that is PID is still alive, if theThe PID process has stopped and throws an exception if it isThe kill signal is not sent while running.

5, socket monitoring a specific port
#!/usr/bin/env python#coding:utf-8import socket, time, Sysdef applicationinstance ():    try:            global s        = Socket.socket ()        host = Socket.gethostname ()        S.bind ((host, 60123))    except:        print "instance is running ... "        sys.exit (0) If __name__ = =" __main__ ":    applicationinstance () while    True:        print ' running ... '        Time.sleep (1)
This function can be implemented using adorners for ease of reuse (the effect is the same as above):
#!/usr/bin/env python#coding:utf-8import socket, time, Sysimport functools# uses adorners to implement Def applicationinstance (func):    @functools. Wraps (func)    def Fun (*args,**kwargs):        import Socket        Try:            global s            s = Socket.socket ()            host = Socket.gethostname ()            S.bind ((host, 60123))        except:            print (' already have an Instance ... ')            return None        return func (*args,**kwargs)    return fun@applicationinstancedef main (): While    True:        print ' running ... '        time.sleep (1) if __name__ = = "__main__":    Main ()

Iv. Summary(1) Daemon and single script running in the actual application of the more important, the method is more, you can choose the appropriate to modify , you can make them into a separate class or template, and then sub-class implementation of the Custom.
(2) Daemon monitoring process Auto-recovery avoids the use of nohup and &, and with shell scripts can save a lot of time to start the trouble of hanging off the server.
(3) If there is better design and ideas, can leave a message at any time, thank you first!

Python example five Python daemon and script singleton run

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.