[Zope-Checkins] CVS: Zope/lib/python/zdaemon - zdaemon.py:1.22.2.1 Daemon.py:1.11.4.5 __init__.py:1.4.4.1 Heartbeat.py:NONE SignalHandler.py:NONE

Chris McDonough chrism@zope.com
Sun, 24 Nov 2002 18:53:59 -0500


Update of /cvs-repository/Zope/lib/python/zdaemon
In directory cvs.zope.org:/tmp/cvs-serv13409

Modified Files:
      Tag: chrism-install-branch
	Daemon.py __init__.py 
Added Files:
      Tag: chrism-install-branch
	zdaemon.py 
Removed Files:
      Tag: chrism-install-branch
	Heartbeat.py SignalHandler.py 
Log Message:
Merge with HEAD.


=== Added File Zope/lib/python/zdaemon/zdaemon.py === (704/804 lines abridged)
#! /usr/bin/env python

"""
zdaemon -- run an application as a daemon.

Usage: python zdaemon.py [zdaemon-options] program [program-arguments]
Or:    python zdaemon.py -c [command]

Options:
  -b SECONDS -- set backoff limit to SECONDS (default 10; see below)
  -c -- client mode, to sends a command to the daemon manager; see below
  -d -- run as a proper daemon; fork a background process, close files etc.
  -f -- run forever (by default, exit when the backoff limit is exceeded)
  -h -- print usage message and exit
  -s SOCKET -- Unix socket name for client communication (default "zdsock")
  -u USER -- run as this user (or numeric uid)
  -x LIST -- list of fatal exit codes (default "0,2"; use "" to disable)
  -z DIRECTORY -- directory to chdir into when using -d; default "/"
  program [program-arguments] -- an arbitrary application to run

Client mode options:
  -s SOCKET -- socket name (a Unix pathname) for client communication
  [command] -- the command to send to the daemon manager (default "status")

Client commands are:
  help -- return command help
  status -- report application status (this is the default command)
  kill [signal] -- send a signal to the application
                   (default signal is SIGTERM)
  start -- start the application if not already running
  stop -- stop the application if running; daemon manager keeps running
  restart -- stop followed by start
  exit -- stop the application and exit

This daemon manager has two purposes: it restarts the application when
it dies, and (when requested to do so with the -d option) it runs the
application in the background, detached from the foreground tty
session that started it (if any).

Important: if at any point the application exits with an exit status
listed by the -x option, it is not restarted.  Any other form of
termination (either being killed by a signal or exiting with an exit
status not listed in the -x option) causes it to be restarted.

Backoff limit: when the application exits (nearly) immediately after a
restart, the daemon manager starts slowing down by delaying between
restarts.  The delay starts at 1 second and is increased by one on
each restart up to the backoff limit given by the -b option; it is
reset when the application runs for more than the backoff limit
seconds.  By default, when the delay reaches the backoff limit, the

[-=- -=- -=- 704 lines omitted -=- -=- -=-]

            iscore = sts & 0x80
        if iscore:
            msg += " (core dumped)"
        return -1, msg
    else:
        msg = "unknown termination cause 0x%04x" % sts
        return -1, msg

_signames = None

def signame(sig):
    """Return a symbolic name for a signal.

    Return "signal NNN" if there is no corresponding SIG name in the
    signal module.
    """

    if _signames is None:
        _init_signames()
    return _signames.get(sig) or "signal %d" % sig

def _init_signames():
    global _signames
    d = {}
    for k, v in signal.__dict__.items():
        k_startswith = getattr(k, "startswith", None)
        if k_startswith is None:
            continue
        if k_startswith("SIG") and not k_startswith("SIG_"):
            d[v] = k
    _signames = d

def get_path():
    """Return a list corresponding to $PATH, or a default."""
    path = ["/bin", "/usr/bin", "/usr/local/bin"]
    if os.environ.has_key("PATH"):
        p = os.environ["PATH"]
        if p:
            path = p.split(os.pathsep)
    return path

# Main program

def main(args=None):
    assert os.name == "posix", "This code makes many Unix-specific assumptions"
    d = Daemonizer()
    d.main(args)

if __name__ == "__main__":
    main()


=== Zope/lib/python/zdaemon/Daemon.py 1.11.4.4 => 1.11.4.5 ===
--- Zope/lib/python/zdaemon/Daemon.py:1.11.4.4	Sat Oct 26 15:51:53 2002
+++ Zope/lib/python/zdaemon/Daemon.py	Sun Nov 24 18:53:58 2002
@@ -13,7 +13,6 @@
 ##############################################################################
 
 import os, sys, time, signal
-from ZDaemonLogging import pstamp
 import zLOG
 
 pyth = sys.executable
@@ -57,14 +56,15 @@
                     signal.signal(sig, SignalPasser(pid))
                 pstamp('Started subprocess: pid %s' % pid, zLOG.INFO)
                 write_pidfile(pidfile)
-                p,s = wait(pid) # waitpid will block until child exit
+                p, s = wait(pid) # waitpid will block until child exit
+                log_pid(p, s)
                 if s:
                     # continue and restart because our child died
                     # with a nonzero exit code, meaning he bit it in
                     # an unsavory way (likely a segfault or something)
-                    log_pid(p, s)
                     continue
                 else:
+                    pstamp("zdaemon exiting", zLOG.INFO)
                     # no need to restart, our child wanted to die.
                     raise DieNow
 
@@ -142,6 +142,9 @@
             startswith = getattr(k, 'startswith', None)
             if startswith is None:
                 continue
-            if startswith('SIG'):
+            if startswith('SIG') and not startswith('SIG_'):
                 _signals[v] = k
     return _signals.get(n, 'unknown')
+
+def pstamp(message, sev):
+    zLOG.LOG("zdaemon", sev, message)


=== Zope/lib/python/zdaemon/__init__.py 1.4 => 1.4.4.1 ===
--- Zope/lib/python/zdaemon/__init__.py:1.4	Wed Aug 14 18:12:52 2002
+++ Zope/lib/python/zdaemon/__init__.py	Sun Nov 24 18:53:58 2002
@@ -12,46 +12,6 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
-"""
-
-zinit, slightly smarter server manager and ZServer startup script.
-
-  zinit will:
-
-    - Fork a parent and a child
-
-    - restart the child if it dies
-
-    - write a pid file so you can kill (the parent)
-
-    - reports the childs pid to stdout so you can kill that too
-
-TODO
-
-  - Have the parent reap the children when it dies
-
-  - etc.
-
-"""
+"""zdaemon -- a package to manage a daemon application."""
 
 from Daemon import run
-
-# XXX Is the following a useful feature?
-
-def main():
-    import sys
-    argv=sys.argv[1:]
-    if argv and argv[0][:2]=='-p':
-        pidf=argv[0][2:]
-        del argv[0]
-    else:
-        pidf=''
-
-    if not argv:
-        print __doc__ % vars()
-        print
-        print 'Error: no script given'
-
-    run(argv, pidf)
-
-if __name__ == '__main__': main()

=== Removed File Zope/lib/python/zdaemon/Heartbeat.py ===

=== Removed File Zope/lib/python/zdaemon/SignalHandler.py ===