Package logilab-common-0 :: Package 36 :: Package 1 :: Module daemon
[frames] | no frames]

Source Code for Module logilab-common-0.36.1.daemon

  1  """A daemon mix-in class. 
  2   
  3  :copyright: 2000-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 
  4  :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr 
  5  :license: General Public License version 2 - http://www.gnu.org/licenses 
  6  """ 
  7  __docformat__ = "restructuredtext en" 
  8   
  9  import os, signal, sys, time 
 10  from logilab.common.logger import make_logger, LOG_ALERT, LOG_NOTICE 
 11   
12 -class DaemonMixIn:
13 """Mixin to make a daemon from watchers/queriers. 14 """ 15
16 - def __init__(self, configmod) :
17 self.delay = configmod.DELAY 18 self.name = str(self.__class__).split('.')[-1] 19 self._pid_file = os.path.join('/tmp', '%s.pid'%self.name) 20 if os.path.exists(self._pid_file): 21 raise Exception('''Another instance of %s must be running. 22 If it i not the case, remove the file %s''' % (self.name, self._pid_file)) 23 self._alive = 1 24 self._sleeping = 0 25 treshold = configmod.LOG_TRESHOLD 26 if configmod.NODETACH: 27 configmod.log = make_logger('print', treshold, self.name).log 28 else: 29 configmod.log = make_logger('syslog', treshold, self.name).log 30 self.config = configmod
31
32 - def _daemonize(self):
33 if not self.config.NODETACH: 34 # fork so the parent can exist 35 if (os.fork()): 36 return -1 37 # deconnect from tty and create a new session 38 os.setsid() 39 # fork again so the parent, (the session group leader), can exit. 40 # as a non-session group leader, we can never regain a controlling 41 # terminal. 42 if (os.fork()): 43 return -1 44 # move to the root to avoit mount pb 45 os.chdir('/') 46 # set paranoid umask 47 os.umask(077) 48 # write pid in a file 49 f = open(self._pid_file, 'w') 50 f.write(str(os.getpid())) 51 f.close() 52 # close standard descriptors 53 sys.stdin.close() 54 sys.stdout.close() 55 sys.stderr.close() 56 # put signal handler 57 signal.signal(signal.SIGTERM, self.signal_handler) 58 signal.signal(signal.SIGHUP, self.signal_handler)
59 60
61 - def run(self):
62 """ optionaly go in daemon mode and 63 do what concrete classe has to do and pauses for delay between runs 64 If self.delay is negative, do a pause before starting 65 """ 66 if self._daemonize() == -1: 67 return 68 self.config.log(LOG_NOTICE, '%s instance started' % self.name) 69 if self.delay < 0: 70 self.delay = -self.delay 71 time.sleep(self.delay) 72 while 1: 73 try: 74 self._run() 75 except Exception, e: 76 # display for info, sleep, and hope the problem will be solved 77 # later. 78 self.config.log(LOG_ALERT, 'Internal error: %s'%(e)) 79 if not self._alive: 80 break 81 try: 82 self._sleeping = 1 83 time.sleep(self.delay) 84 self._sleeping = 0 85 except SystemExit: 86 break 87 self.config.log(LOG_NOTICE, '%s instance exited'%self.name) 88 # remove pid file 89 os.remove(self._pid_file)
90
91 - def signal_handler(self, sig_num, stack_frame):
92 if sig_num == signal.SIGTERM: 93 if self._sleeping: 94 # we are sleeping so we can exit without fear 95 self.config.log(LOG_NOTICE, 'exit on SIGTERM') 96 sys.exit(0) 97 else: 98 self.config.log(LOG_NOTICE, 'exit on SIGTERM (on next turn)') 99 self._alive = 0 100 elif sig_num == signal.SIGHUP: 101 self.config.log(LOG_NOTICE, 'reloading configuration on SIGHUP') 102 reload(self.config)
103
104 - def _run(self):
105 """should be overidden in the mixed class""" 106 raise NotImplementedError()
107 108 ## command line utilities ###################################################### 109 110 L_OPTIONS = ["help", "log=", "delay=", 'no-detach'] 111 S_OPTIONS = 'hl:d:n' 112 122
123 -def handle_option(modconfig, opt_name, opt_value, help_meth):
124 if opt_name in ('-h','--help'): 125 help_meth() 126 sys.exit(0) 127 elif opt_name in ('-l','--log'): 128 modconfig.LOG_TRESHOLD = int(opt_value) 129 elif opt_name in ('-d', '--delay'): 130 modconfig.DELAY = int(opt_value) 131 elif opt_name in ('-n', '--no-detach'): 132 modconfig.NODETACH = 1
133