[Python-modules-commits] [python-daemonocle] 01/03: import srcpkgname_1.0.orig.tar.gz

Adrian Alves alvesadrian-guest at moszumanska.debian.org
Sun Apr 24 16:11:33 UTC 2016


This is an automated email from the git hooks/post-receive script.

alvesadrian-guest pushed a commit to branch master
in repository python-daemonocle.

commit b7a4c4b868b320b9217723afc376dbcbfa22708a
Author: Adrian Alves <aalves at gmail.com>
Date:   Sun Apr 24 13:07:36 2016 -0300

    import srcpkgname_1.0.orig.tar.gz
---
 LICENSE                                  |  21 ++
 MANIFEST.in                              |   2 +
 PKG-INFO                                 | 459 ++++++++++++++++++++++++
 README.rst                               | 447 +++++++++++++++++++++++
 daemonocle.egg-info/PKG-INFO             | 459 ++++++++++++++++++++++++
 daemonocle.egg-info/SOURCES.txt          |  13 +
 daemonocle.egg-info/dependency_links.txt |   1 +
 daemonocle.egg-info/requires.txt         |   2 +
 daemonocle.egg-info/top_level.txt        |   1 +
 daemonocle/__init__.py                   |  19 +
 daemonocle/cli.py                        |  76 ++++
 daemonocle/daemon.py                     | 587 +++++++++++++++++++++++++++++++
 daemonocle/exceptions.py                 |   6 +
 setup.cfg                                |   5 +
 setup.py                                 |  31 ++
 15 files changed, 2129 insertions(+)

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..387e0bf
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Jonathan Robson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..9d5d250
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,2 @@
+include LICENSE
+include README.rst
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..df3870f
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,459 @@
+Metadata-Version: 1.1
+Name: daemonocle
+Version: 0.8
+Summary: A Python library for creating super fancy Unix daemons
+Home-page: http://github.com/jnrbsn/daemonocle
+Author: Jonathan Robson
+Author-email: jnrbsn at gmail.com
+License: MIT
+Description: daemonocle is a library for creating your own Unix-style daemons written in Python. It solves many
+        problems that other daemon libraries have and provides some really useful features you don't often
+        see in other daemons.
+        
+        .. contents:: **Table of Contents**
+          :backlinks: none
+        
+        Installation
+        ------------
+        
+        To install via pip::
+        
+            pip install daemonocle
+        
+        Or download the source code and install manually::
+        
+            git clone https://github.com/jnrbsn/daemonocle.git
+            cd daemonocle/
+            python setup.py install
+        
+        Basic Usage
+        -----------
+        
+        Here's a **really really** basic example:
+        
+        .. code:: python
+        
+            import sys
+            import time
+        
+            import daemonocle
+        
+            # This is your daemon. It sleeps, and then sleeps again.
+            def main():
+                while True:
+                    time.sleep(10)
+        
+            if __name__ == '__main__':
+                daemon = daemonocle.Daemon(
+                    worker=main,
+                    pidfile='/var/run/daemonocle_example.pid',
+                )
+                daemon.do_action(sys.argv[1])
+        
+        And here's the same example with logging and a `Shutdown Callback`_:
+        
+        .. code:: python
+        
+            import logging
+            import sys
+            import time
+        
+            import daemonocle
+        
+            def cb_shutdown(message, code):
+                logging.info('Daemon is stopping')
+                logging.debug(message)
+        
+            def main():
+                logging.basicConfig(
+                    filename='/var/log/daemonocle_example.log',
+                    level=logging.DEBUG, format='%(asctime)s [%(levelname)s] %(message)s',
+                )
+                logging.info('Daemon is starting')
+                while True:
+                    logging.debug('Still running')
+                    time.sleep(10)
+        
+            if __name__ == '__main__':
+                daemon = daemonocle.Daemon(
+                    worker=main,
+                    shutdown_callback=cb_shutdown,
+                    pidfile='/var/run/daemonocle_example.pid',
+                )
+                daemon.do_action(sys.argv[1])
+        
+        And here's what it looks like when you run it::
+        
+            user at host:~$ python example.py start
+            Starting example.py ... OK
+            user at host:~$ python example.py status
+            example.py -- pid: 1234, status: running, uptime: 1m, %cpu: 0.0, %mem: 0.0
+            user at host:~$ python example.py stop
+            Stopping example.py ... OK
+            user at host:~$ cat /var/log/daemonocle_example.log
+            2014-05-04 12:39:21,090 [INFO] Daemon is starting
+            2014-05-04 12:39:21,091 [DEBUG] Still running
+            2014-05-04 12:39:31,091 [DEBUG] Still running
+            2014-05-04 12:39:41,091 [DEBUG] Still running
+            2014-05-04 12:39:51,093 [DEBUG] Still running
+            2014-05-04 12:40:01,094 [DEBUG] Still running
+            2014-05-04 12:40:07,113 [INFO] Daemon is stopping
+            2014-05-04 12:40:07,114 [DEBUG] Terminated by SIGTERM (15)
+        
+        For more details, see the `Detailed Usage`_ section below.
+        
+        Rationale
+        ---------
+        
+        If you think about it, a lot of Unix daemons don't really know what the hell they're doing. Have you
+        ever found yourself in a situation that looked something like this? ::
+        
+            user at host:~$ sudo example start
+            starting example ... ok
+            user at host:~$ ps aux | grep example
+            user      1234  0.0  0.0   1234  1234 pts/1    S+   12:34   0:00 grep example
+            user at host:~$ sudo example start
+            starting example ... ok
+            user at host:~$ echo $?
+            0
+            user at host:~$ tail -f /var/log/example.log
+            ...
+        
+        Or something like this? ::
+        
+            user at host:~$ sudo example stop
+            stopping example ... ok
+            user at host:~$ ps aux | grep example
+            user       123  0.0  0.0   1234  1234 ?        Ss   00:00   0:00 /usr/local/bin/example
+            user      1234  0.0  0.0   1234  1234 pts/1    S+   12:34   0:00 grep example
+            user at host:~$ sudo example stop
+            stopping example ... ok
+            user at host:~$ ps aux | grep example
+            user       123  0.0  0.0   1234  1234 ?        Ss   00:00   0:00 /usr/local/bin/example
+            user      1240  0.0  0.0   1234  1234 pts/1    S+   12:34   0:00 grep example
+            user at host:~$ sudo kill -9 123
+            ...
+        
+        Or something like this? ::
+        
+            user at host:~$ sudo example status
+            Usage: example {start|stop|restart}
+            user at host:~$ ps aux | grep example
+            ...
+        
+        These are just a few examples of unnecessarily common problems. It doesn't have to be this way.
+        
+            **Note:** You might be thinking, "Why not just write a smarter start/stop shell script wrapper
+            for your daemon that checks whether or not it actually started, actually stopped, etc.?"
+            Seriously? **It doesn't have to be this way.** I believe daemons should be more self-aware. They
+            should handle their own problems most of the time, and your start/stop script should only be a
+            very thin wrapper around your daemon or simply a symlink to your daemon.
+        
+        The Problem
+        ~~~~~~~~~~~
+        
+        If you've ever dug deep into the nitty-gritty details of how daemonization works, you're probably
+        familiar with the `standard "double fork" paradigm <http://bit.ly/stevens-daemon>`_ first introduced
+        by W. Richard Stevens in the book `Advanced Programming in the UNIX Environment
+        <http://amzn.com/0321637739>`_. One of the problems with the standard way to implement this is that
+        if the final child dies immediately when it gets around to doing real work, the original parent
+        process (the one that actually had control of your terminal) is long gone. So all you know is that
+        the process got forked, but you have no idea if it actually kept running for more than a fraction of
+        a second. And let's face it, one of the most likely times for a daemon to die is immediately after
+        it starts (due to bad configuration, permissions, etc.).
+        
+        The next problem mentioned in the section above is when you try to stop a daemon, it doesn't
+        actually stop, and you have no idea that it didn't actually stop. This happens when a process
+        doesn't respond properly to a ``SIGTERM`` signal. It happens more often than it should. The problem
+        is not necessarily the fact that it didn't stop. It's the fact that you didn't *know* that it didn't
+        stop. The start/stop script knows that it successfully sent the signal and so it assumes success.
+        This also becomes a problem when your ``restart`` command blindly calls ``stop`` and then ``start``,
+        because it will try to start a new instance of the daemon before the previous one has exited.
+        
+        These are the biggest problems most daemons have in my opinion. daemonocle solves these problems and
+        provides many other "fancy" features.
+        
+        The Solution
+        ~~~~~~~~~~~~
+        
+        The problem with the daemon immediately dying on startup and you not knowing about it is solved by
+        having the first child (the immediate parent of the final child) sleep for one second and then call
+        ``os.waitpid(pid, os.WNOHANG)`` to see if the process is still running. This is what daemonocle
+        does. So if you're daemon dies within one second of starting, you'll know about it.
+        
+        This problem with the daemon not stopping and you not knowing about it is solved by simply waiting
+        for the process to finish (with a timeout). This is what daemonocle does. (Note: When a timeout
+        occurs, it doesn't try to send a ``SIGKILL``. This is not always what you'd want and often not a
+        good idea.)
+        
+        Other Useful Features
+        ~~~~~~~~~~~~~~~~~~~~~
+        
+        Below are some other useful features that daemononcle provides that you might not find elsewhere.
+        
+        The ``status`` Action
+        +++++++++++++++++++++
+        
+        There is a ``status`` action that not only displays whether or not the daemon is running and its
+        PID, but also the uptime of the daemon and the % CPU and % memory usage of all the processes in the
+        same process group as the daemon (which are probably its children). So if you have a daemon that
+        launches mulitple worker processes, the ``status`` action will show the % CPU and % memory usage of
+        all the workers combined.
+        
+        It might look something like this::
+        
+            user at host:~$ python example.py status
+            example.py -- pid: 1234, status: running, uptime: 12d 3h 4m, %cpu: 12.4, %mem: 4.5
+        
+        Slightly Smarter ``restart`` Action
+        +++++++++++++++++++++++++++++++++++
+        
+        Have you ever tried to restart a daemon only to realize that it's not actually running? Let me
+        guess: it just gave you an error and didn't start the daemon. A lot of the time this is not a
+        problem, but if you're trying to restart the daemon in an automated way, it's more annoying to have
+        to check if it's running and do either a ``start`` or ``restart`` accordingly. With daemonocle, if
+        you try to restart a daemon that's not running, it will give you a warning saying that it wasn't
+        running and then start the daemon. This is often what people expect.
+        
+        Self-Reload
+        +++++++++++
+        
+        Daemons that use daemonocle have the ability to reload themselves by simply calling
+        ``daemon.reload()`` where ``daemon`` is your ``daemonocle.Daemon`` instance. The execution of the
+        current daemon halts wherever ``daemon.reload()`` was called, and a new daemon is started up to
+        replace the current one. From your code's perspective, it's pretty much the same as a doing a
+        ``restart`` except that it's initiated from within the daemon itself and there's no signal handling
+        involved. Here's a basic example of a daemon that watches a config file and reloads itself when the
+        config file changes:
+        
+        .. code:: python
+        
+            import os
+            import sys
+            import time
+        
+            import daemonocle
+        
+            class FileWatcher(object):
+        
+                def __init__(self, filename, daemon):
+                    self._filename = filename
+                    self._daemon = daemon
+                    self._file_mtime = os.stat(self._filename).st_mtime
+        
+                def file_has_changed(self):
+                    current_mtime = os.stat(self._filename).st_mtime
+                    if current_mtime != self._file_mtime:
+                        self._file_mtime = current_mtime
+                        return True
+                    return False
+        
+                def watch(self):
+                    while True:
+                        if self.file_has_changed():
+                            self._daemon.reload()
+                        time.sleep(1)
+        
+            if __name__ == '__main__':
+                daemon = daemonocle.Daemon(pidfile='/var/run/daemonocle_example.pid')
+                fw = FileWatcher(filename='/etc/daemonocle_example.conf', daemon=daemon)
+                daemon.worker = fw.watch
+                daemon.do_action(sys.argv[1])
+        
+        Shutdown Callback
+        +++++++++++++++++
+        
+        You may have noticed from the `Basic Usage`_ section above that a ``shutdown_callback`` was defined.
+        This function gets called whenever the daemon is shutting down in a catchable way, which should be
+        most of the time except for a ``SIGKILL`` or if your server crashes unexpectedly or loses power or
+        something like that. This function can be used for doing any sort of cleanup that your daemon needs
+        to do. Also, if you want to log (to the logger of your choice) the reason for the shutdown and the
+        intended exit code, you can use the ``message`` and ``code`` arguments that will be passed to your
+        callback (your callback must take these two arguments).
+        
+        Non-Detached Mode
+        +++++++++++++++++
+        
+        This is not particularly interesting per se, but it's worth noting that in non-detached mode, your
+        daemon will do everything else you've configured it to do (i.e. ``setuid``, ``setgid``, ``chroot``,
+        etc.) except actually detaching from your terminal. So while you're testing, you can get an
+        extremely accurate view of how your daemon will behave in the wild. It's also worth noting that
+        self-reloading works in non-detached mode, which was a little tricky to figure out initially.
+        
+        File Descriptor Handling
+        ++++++++++++++++++++++++
+        
+        One of the things that daemons typically do is close all open file descriptors and establish new
+        ones for ``STDIN``, ``STDOUT``, ``STDERR`` that just point to ``/dev/null``. This is fine most of
+        the time, but if your worker is an instance method of a class that opens files in its ``__init__()``
+        method, then you'll run into problems if you're not careful. This is also a problem if you're
+        importing a module that leaves open files behind. For example, importing the
+        `random <https://docs.python.org/3/library/random.html>`_ standard library module in Python 3
+        results in an open file descriptor for ``/dev/urandom``.
+        
+        Since this "feature" of daemons often causes more problems than it solves, and the problems it
+        causes sometimes have strange side-effects that make it very difficult to troubleshoot, this feature
+        is optional and disabled by default in daemonocle via the ``close_open_files`` option.
+        
+        Detailed Usage
+        --------------
+        
+        The ``daemonocle.Daemon`` class is the main class for creating a daemon using daemonocle. Here's the
+        constructor signature for the class:
+        
+        .. code:: python
+        
+            class daemonocle.Daemon(
+                worker=None, shutdown_callback=None, prog=None, pidfile=None, detach=True,
+                uid=None, gid=None, workdir='/', chrootdir=None, umask=022, stop_timeout=10,
+                close_open_files=False)
+        
+        And here are descriptions of all the arguments:
+        
+        **worker**
+            The function that does all the work for your daemon.
+        
+        **shutdown_callback**
+            This will get called anytime the daemon is shutting down. It should take a ``message`` and a
+            ``code`` argument. The message is a human readable message that explains why the daemon is
+            shutting down. It might useful to log this message. The code is the exit code with which it
+            intends to exit. See `Shutdown Callback`_ for more details.
+        
+        **prog**
+            The name of your program to use in output messages. Default: ``os.path.basename(sys.argv[0])``
+        
+        **pidfile**
+            The path to a PID file to use. It's not required to use a PID file, but if you don't, you won't
+            be able to use all the features you might expect. Make sure the user your daemon is running as
+            has permission to write to the directory this file is in.
+        
+        **detach**
+            Whether or not to detach from the terminal and go into the background. See `Non-Detached Mode`_
+            for more details. Default: ``True``
+        
+        **uid**
+            The user ID to switch to when the daemon starts. The default is not to switch users.
+        
+        **gid**
+            The group ID to switch to when the daemon starts. The default is not to switch groups.
+        
+        **workdir**
+            The path to a directory to change to when the daemon starts. Note that a file system cannot be
+            unmounted if a process has its working directory on that file system. So if you change the
+            default, be careful about what you change it to. Default: ``"/"``
+        
+        **chrootdir**
+            The path to a directory to set as the effective root directory when the daemon starts. The
+            default is not to do anything.
+        
+        **umask**
+            The file creation mask ("umask") for the process. Default: ``022``
+        
+        **stop_timeout**
+            Number of seconds to wait for the daemon to stop before throwing an error. Default: ``10``
+        
+        **close_open_files**
+            Whether or not to close all open files when the daemon detaches. Default: ``False``
+        
+        Actions
+        ~~~~~~~
+        
+        The default actions are ``start``, ``stop``, ``restart``, and ``status``. You can get a list of
+        available actions using the ``daemonocle.Daemon.list_actions()`` method. The recommended way to call
+        an action is using the ``daemonocle.Daemon.do_action(action)`` method. The string name of an action
+        is the same as the method name except with dashes in place of underscores.
+        
+        If you want to create your own actions, simply subclass ``daemonocle.Daemon`` and add the
+        ``@daemonocle.expose_action`` decorator to your action method, and that's it.
+        
+        Here's an example:
+        
+        .. code:: python
+        
+            import daemonocle
+        
+            class MyDaemon(daemonocle.Daemon):
+        
+                @daemonocle.expose_action
+                def full_status(self):
+                    """Get more detailed status of the daemon."""
+                    pass
+        
+        Then, if you did the basic ``daemon.do_action(sys.argv[1])`` like in all the examples above, you can
+        call your action with a command like ``python example.py full-status``.
+        
+        Integration with mitsuhiko's click
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        
+        daemonocle also provides an integration with `click <http://click.pocoo.org/>`_, the "composable
+        command line utility". The integration is in the form of a custom command class
+        ``daemonocle.cli.DaemonCLI`` that you can use in conjunction with the ``@click.command()`` decorator
+        to automatically generate a command line interface with subcommands for all your actions. It also
+        automatically daemonizes the decorated function. The decorated function becomes the worker, and the
+        actions are automatically mapped from click to daemonocle.
+        
+        Here's an example:
+        
+        .. code:: python
+        
+            import time
+        
+            import click
+            from daemonocle.cli import DaemonCLI
+        
+            @click.command(cls=DaemonCLI, daemon_params={'pidfile': '/var/run/example.pid'})
+            def main():
+                """This is my awesome daemon. It pretends to do work in the background."""
+                while True:
+                    time.sleep(10)
+        
+            if __name__ == '__main__':
+                main()
+        
+        Running this example would look something like this::
+        
+            user at host:~$ python example.py --help
+            Usage: example.py [<options>] <command> [<args>]...
+        
+              This is my awesome daemon. It pretends to do work in the background.
+        
+            Options:
+              --help  Show this message and exit.
+        
+            Commands:
+              start    Start the daemon.
+              stop     Stop the daemon.
+              restart  Stop then start the daemon.
+              status   Get the status of the daemon.
+            user at host:~$ python example.py start --help
+            Usage: example.py start [<options>]
+        
+              Start the daemon.
+        
+            Options:
+              --debug  Do NOT detach and run in the background.
+              --help   Show this message and exit.
+        
+        The ``daemonocle.cli.DaemonCLI`` class also accepts a ``daemon_class`` argument that can be a
+        subclass of ``daemonocle.Daemon``. It will use your custom class, automatically create subcommands
+        for any custom actions you've defined, and use the docstrings of the action methods as the help text
+        just like click usually does.
+        
+        This integration is entirely optional. daemonocle doesn't enforce any sort of argument parsing. You
+        can use argparse, optparse, or just plain ``sys.argv`` if you want.
+        
+        Bugs, Requests, Questions, etc.
+        -------------------------------
+        
+        Please create an `issue on GitHub <https://github.com/jnrbsn/daemonocle/issues>`_.
+        
+Keywords: daemon daemonize fork unix cli
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..77eefac
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,447 @@
+daemonocle
+==========
+
+*A Python library for creating super fancy Unix daemons*
+
+-----
+
+daemonocle is a library for creating your own Unix-style daemons written in Python. It solves many
+problems that other daemon libraries have and provides some really useful features you don't often
+see in other daemons.
+
+.. contents:: **Table of Contents**
+  :backlinks: none
+
+Installation
+------------
+
+To install via pip::
+
+    pip install daemonocle
+
+Or download the source code and install manually::
+
+    git clone https://github.com/jnrbsn/daemonocle.git
+    cd daemonocle/
+    python setup.py install
+
+Basic Usage
+-----------
+
+Here's a **really really** basic example:
+
+.. code:: python
+
+    import sys
+    import time
+
+    import daemonocle
+
+    # This is your daemon. It sleeps, and then sleeps again.
+    def main():
+        while True:
+            time.sleep(10)
+
+    if __name__ == '__main__':
+        daemon = daemonocle.Daemon(
+            worker=main,
+            pidfile='/var/run/daemonocle_example.pid',
+        )
+        daemon.do_action(sys.argv[1])
+
+And here's the same example with logging and a `Shutdown Callback`_:
+
+.. code:: python
+
+    import logging
+    import sys
+    import time
+
+    import daemonocle
+
+    def cb_shutdown(message, code):
+        logging.info('Daemon is stopping')
+        logging.debug(message)
+
+    def main():
+        logging.basicConfig(
+            filename='/var/log/daemonocle_example.log',
+            level=logging.DEBUG, format='%(asctime)s [%(levelname)s] %(message)s',
+        )
+        logging.info('Daemon is starting')
+        while True:
+            logging.debug('Still running')
+            time.sleep(10)
+
+    if __name__ == '__main__':
+        daemon = daemonocle.Daemon(
+            worker=main,
+            shutdown_callback=cb_shutdown,
+            pidfile='/var/run/daemonocle_example.pid',
+        )
+        daemon.do_action(sys.argv[1])
+
+And here's what it looks like when you run it::
+
+    user at host:~$ python example.py start
+    Starting example.py ... OK
+    user at host:~$ python example.py status
+    example.py -- pid: 1234, status: running, uptime: 1m, %cpu: 0.0, %mem: 0.0
+    user at host:~$ python example.py stop
+    Stopping example.py ... OK
+    user at host:~$ cat /var/log/daemonocle_example.log
+    2014-05-04 12:39:21,090 [INFO] Daemon is starting
+    2014-05-04 12:39:21,091 [DEBUG] Still running
+    2014-05-04 12:39:31,091 [DEBUG] Still running
+    2014-05-04 12:39:41,091 [DEBUG] Still running
+    2014-05-04 12:39:51,093 [DEBUG] Still running
+    2014-05-04 12:40:01,094 [DEBUG] Still running
+    2014-05-04 12:40:07,113 [INFO] Daemon is stopping
+    2014-05-04 12:40:07,114 [DEBUG] Terminated by SIGTERM (15)
+
+For more details, see the `Detailed Usage`_ section below.
+
+Rationale
+---------
+
+If you think about it, a lot of Unix daemons don't really know what the hell they're doing. Have you
+ever found yourself in a situation that looked something like this? ::
+
+    user at host:~$ sudo example start
+    starting example ... ok
+    user at host:~$ ps aux | grep example
+    user      1234  0.0  0.0   1234  1234 pts/1    S+   12:34   0:00 grep example
+    user at host:~$ sudo example start
+    starting example ... ok
+    user at host:~$ echo $?
+    0
+    user at host:~$ tail -f /var/log/example.log
+    ...
+
+Or something like this? ::
+
+    user at host:~$ sudo example stop
+    stopping example ... ok
+    user at host:~$ ps aux | grep example
+    user       123  0.0  0.0   1234  1234 ?        Ss   00:00   0:00 /usr/local/bin/example
+    user      1234  0.0  0.0   1234  1234 pts/1    S+   12:34   0:00 grep example
+    user at host:~$ sudo example stop
+    stopping example ... ok
+    user at host:~$ ps aux | grep example
+    user       123  0.0  0.0   1234  1234 ?        Ss   00:00   0:00 /usr/local/bin/example
+    user      1240  0.0  0.0   1234  1234 pts/1    S+   12:34   0:00 grep example
+    user at host:~$ sudo kill -9 123
+    ...
+
+Or something like this? ::
+
+    user at host:~$ sudo example status
+    Usage: example {start|stop|restart}
+    user at host:~$ ps aux | grep example
+    ...
+
+These are just a few examples of unnecessarily common problems. It doesn't have to be this way.
+
+    **Note:** You might be thinking, "Why not just write a smarter start/stop shell script wrapper
+    for your daemon that checks whether or not it actually started, actually stopped, etc.?"
+    Seriously? **It doesn't have to be this way.** I believe daemons should be more self-aware. They
+    should handle their own problems most of the time, and your start/stop script should only be a
+    very thin wrapper around your daemon or simply a symlink to your daemon.
+
+The Problem
+~~~~~~~~~~~
+
+If you've ever dug deep into the nitty-gritty details of how daemonization works, you're probably
+familiar with the `standard "double fork" paradigm <http://bit.ly/stevens-daemon>`_ first introduced
+by W. Richard Stevens in the book `Advanced Programming in the UNIX Environment
+<http://amzn.com/0321637739>`_. One of the problems with the standard way to implement this is that
+if the final child dies immediately when it gets around to doing real work, the original parent
+process (the one that actually had control of your terminal) is long gone. So all you know is that
+the process got forked, but you have no idea if it actually kept running for more than a fraction of
+a second. And let's face it, one of the most likely times for a daemon to die is immediately after
+it starts (due to bad configuration, permissions, etc.).
+
+The next problem mentioned in the section above is when you try to stop a daemon, it doesn't
+actually stop, and you have no idea that it didn't actually stop. This happens when a process
+doesn't respond properly to a ``SIGTERM`` signal. It happens more often than it should. The problem
+is not necessarily the fact that it didn't stop. It's the fact that you didn't *know* that it didn't
+stop. The start/stop script knows that it successfully sent the signal and so it assumes success.
+This also becomes a problem when your ``restart`` command blindly calls ``stop`` and then ``start``,
+because it will try to start a new instance of the daemon before the previous one has exited.
+
+These are the biggest problems most daemons have in my opinion. daemonocle solves these problems and
+provides many other "fancy" features.
+
+The Solution
+~~~~~~~~~~~~
+
+The problem with the daemon immediately dying on startup and you not knowing about it is solved by
+having the first child (the immediate parent of the final child) sleep for one second and then call
+``os.waitpid(pid, os.WNOHANG)`` to see if the process is still running. This is what daemonocle
+does. So if you're daemon dies within one second of starting, you'll know about it.
+
+This problem with the daemon not stopping and you not knowing about it is solved by simply waiting
+for the process to finish (with a timeout). This is what daemonocle does. (Note: When a timeout
+occurs, it doesn't try to send a ``SIGKILL``. This is not always what you'd want and often not a
+good idea.)
+
+Other Useful Features
+~~~~~~~~~~~~~~~~~~~~~
+
+Below are some other useful features that daemononcle provides that you might not find elsewhere.
+
+The ``status`` Action
++++++++++++++++++++++
+
+There is a ``status`` action that not only displays whether or not the daemon is running and its
+PID, but also the uptime of the daemon and the % CPU and % memory usage of all the processes in the
+same process group as the daemon (which are probably its children). So if you have a daemon that
+launches mulitple worker processes, the ``status`` action will show the % CPU and % memory usage of
+all the workers combined.
+
+It might look something like this::
+
+    user at host:~$ python example.py status
+    example.py -- pid: 1234, status: running, uptime: 12d 3h 4m, %cpu: 12.4, %mem: 4.5
+
+Slightly Smarter ``restart`` Action
++++++++++++++++++++++++++++++++++++
+
+Have you ever tried to restart a daemon only to realize that it's not actually running? Let me
+guess: it just gave you an error and didn't start the daemon. A lot of the time this is not a
+problem, but if you're trying to restart the daemon in an automated way, it's more annoying to have
+to check if it's running and do either a ``start`` or ``restart`` accordingly. With daemonocle, if
+you try to restart a daemon that's not running, it will give you a warning saying that it wasn't
+running and then start the daemon. This is often what people expect.
+
+Self-Reload
++++++++++++
+
+Daemons that use daemonocle have the ability to reload themselves by simply calling
+``daemon.reload()`` where ``daemon`` is your ``daemonocle.Daemon`` instance. The execution of the
+current daemon halts wherever ``daemon.reload()`` was called, and a new daemon is started up to
+replace the current one. From your code's perspective, it's pretty much the same as a doing a
+``restart`` except that it's initiated from within the daemon itself and there's no signal handling
+involved. Here's a basic example of a daemon that watches a config file and reloads itself when the
+config file changes:
+
+.. code:: python
+
+    import os
+    import sys
+    import time
+
+    import daemonocle
+
+    class FileWatcher(object):
+
+        def __init__(self, filename, daemon):
+            self._filename = filename
+            self._daemon = daemon
+            self._file_mtime = os.stat(self._filename).st_mtime
+
+        def file_has_changed(self):
+            current_mtime = os.stat(self._filename).st_mtime
+            if current_mtime != self._file_mtime:
+                self._file_mtime = current_mtime
+                return True
+            return False
+
+        def watch(self):
+            while True:
+                if self.file_has_changed():
+                    self._daemon.reload()
+                time.sleep(1)
+
+    if __name__ == '__main__':
+        daemon = daemonocle.Daemon(pidfile='/var/run/daemonocle_example.pid')
+        fw = FileWatcher(filename='/etc/daemonocle_example.conf', daemon=daemon)
+        daemon.worker = fw.watch
+        daemon.do_action(sys.argv[1])
+
+Shutdown Callback
++++++++++++++++++
+
+You may have noticed from the `Basic Usage`_ section above that a ``shutdown_callback`` was defined.
+This function gets called whenever the daemon is shutting down in a catchable way, which should be
+most of the time except for a ``SIGKILL`` or if your server crashes unexpectedly or loses power or
+something like that. This function can be used for doing any sort of cleanup that your daemon needs
+to do. Also, if you want to log (to the logger of your choice) the reason for the shutdown and the
+intended exit code, you can use the ``message`` and ``code`` arguments that will be passed to your
+callback (your callback must take these two arguments).
+
+Non-Detached Mode
++++++++++++++++++
+
+This is not particularly interesting per se, but it's worth noting that in non-detached mode, your
+daemon will do everything else you've configured it to do (i.e. ``setuid``, ``setgid``, ``chroot``,
+etc.) except actually detaching from your terminal. So while you're testing, you can get an
+extremely accurate view of how your daemon will behave in the wild. It's also worth noting that
+self-reloading works in non-detached mode, which was a little tricky to figure out initially.
+
+File Descriptor Handling
+++++++++++++++++++++++++
+
+One of the things that daemons typically do is close all open file descriptors and establish new
+ones for ``STDIN``, ``STDOUT``, ``STDERR`` that just point to ``/dev/null``. This is fine most of
+the time, but if your worker is an instance method of a class that opens files in its ``__init__()``
+method, then you'll run into problems if you're not careful. This is also a problem if you're
+importing a module that leaves open files behind. For example, importing the
+`random <https://docs.python.org/3/library/random.html>`_ standard library module in Python 3
+results in an open file descriptor for ``/dev/urandom``.
+
+Since this "feature" of daemons often causes more problems than it solves, and the problems it
+causes sometimes have strange side-effects that make it very difficult to troubleshoot, this feature
+is optional and disabled by default in daemonocle via the ``close_open_files`` option.
+
+Detailed Usage
+--------------
+
+The ``daemonocle.Daemon`` class is the main class for creating a daemon using daemonocle. Here's the
+constructor signature for the class:
+
+.. code:: python
+
+    class daemonocle.Daemon(
+        worker=None, shutdown_callback=None, prog=None, pidfile=None, detach=True,
+        uid=None, gid=None, workdir='/', chrootdir=None, umask=022, stop_timeout=10,
+        close_open_files=False)
+
+And here are descriptions of all the arguments:
+
+**worker**
+    The function that does all the work for your daemon.
+
+**shutdown_callback**
+    This will get called anytime the daemon is shutting down. It should take a ``message`` and a
+    ``code`` argument. The message is a human readable message that explains why the daemon is
+    shutting down. It might useful to log this message. The code is the exit code with which it
+    intends to exit. See `Shutdown Callback`_ for more details.
+
+**prog**
+    The name of your program to use in output messages. Default: ``os.path.basename(sys.argv[0])``
+
+**pidfile**
+    The path to a PID file to use. It's not required to use a PID file, but if you don't, you won't
+    be able to use all the features you might expect. Make sure the user your daemon is running as
+    has permission to write to the directory this file is in.
+
+**detach**
+    Whether or not to detach from the terminal and go into the background. See `Non-Detached Mode`_
+    for more details. Default: ``True``
+
+**uid**
+    The user ID to switch to when the daemon starts. The default is not to switch users.
+
+**gid**
+    The group ID to switch to when the daemon starts. The default is not to switch groups.
+
+**workdir**
+    The path to a directory to change to when the daemon starts. Note that a file system cannot be
+    unmounted if a process has its working directory on that file system. So if you change the
+    default, be careful about what you change it to. Default: ``"/"``
+
+**chrootdir**
+    The path to a directory to set as the effective root directory when the daemon starts. The
+    default is not to do anything.
+
+**umask**
+    The file creation mask ("umask") for the process. Default: ``022``
+
+**stop_timeout**
+    Number of seconds to wait for the daemon to stop before throwing an error. Default: ``10``
+
+**close_open_files**
+    Whether or not to close all open files when the daemon detaches. Default: ``False``
+
+Actions
+~~~~~~~
+
+The default actions are ``start``, ``stop``, ``restart``, and ``status``. You can get a list of
+available actions using the ``daemonocle.Daemon.list_actions()`` method. The recommended way to call
+an action is using the ``daemonocle.Daemon.do_action(action)`` method. The string name of an action
+is the same as the method name except with dashes in place of underscores.
+
+If you want to create your own actions, simply subclass ``daemonocle.Daemon`` and add the
+``@daemonocle.expose_action`` decorator to your action method, and that's it.
+
+Here's an example:
+
+.. code:: python
+
+    import daemonocle
+
+    class MyDaemon(daemonocle.Daemon):
+
+        @daemonocle.expose_action
+        def full_status(self):
+            """Get more detailed status of the daemon."""
+            pass
+
+Then, if you did the basic ``daemon.do_action(sys.argv[1])`` like in all the examples above, you can
+call your action with a command like ``python example.py full-status``.
+
+Integration with mitsuhiko's click
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+daemonocle also provides an integration with `click <http://click.pocoo.org/>`_, the "composable
+command line utility". The integration is in the form of a custom command class
+``daemonocle.cli.DaemonCLI`` that you can use in conjunction with the ``@click.command()`` decorator
+to automatically generate a command line interface with subcommands for all your actions. It also
+automatically daemonizes the decorated function. The decorated function becomes the worker, and the
+actions are automatically mapped from click to daemonocle.
+
+Here's an example:
+
+.. code:: python
+
+    import time
+
+    import click
+    from daemonocle.cli import DaemonCLI
+
+    @click.command(cls=DaemonCLI, daemon_params={'pidfile': '/var/run/example.pid'})
+    def main():
+        """This is my awesome daemon. It pretends to do work in the background."""
+        while True:
+            time.sleep(10)
+
+    if __name__ == '__main__':
+        main()
+
+Running this example would look something like this::
+
+    user at host:~$ python example.py --help
+    Usage: example.py [<options>] <command> [<args>]...
+
+      This is my awesome daemon. It pretends to do work in the background.
+
+    Options:
+      --help  Show this message and exit.
+
+    Commands:
+      start    Start the daemon.
+      stop     Stop the daemon.
+      restart  Stop then start the daemon.
+      status   Get the status of the daemon.
+    user at host:~$ python example.py start --help
+    Usage: example.py start [<options>]
+
+      Start the daemon.
+
+    Options:
+      --debug  Do NOT detach and run in the background.
+      --help   Show this message and exit.
+
+The ``daemonocle.cli.DaemonCLI`` class also accepts a ``daemon_class`` argument that can be a
+subclass of ``daemonocle.Daemon``. It will use your custom class, automatically create subcommands
+for any custom actions you've defined, and use the docstrings of the action methods as the help text
+just like click usually does.
+
+This integration is entirely optional. daemonocle doesn't enforce any sort of argument parsing. You
+can use argparse, optparse, or just plain ``sys.argv`` if you want.
+
+Bugs, Requests, Questions, etc.
+-------------------------------
+
+Please create an `issue on GitHub <https://github.com/jnrbsn/daemonocle/issues>`_.
diff --git a/daemonocle.egg-info/PKG-INFO b/daemonocle.egg-info/PKG-INFO
new file mode 100644
index 0000000..df3870f
--- /dev/null
+++ b/daemonocle.egg-info/PKG-INFO
@@ -0,0 +1,459 @@
+Metadata-Version: 1.1
+Name: daemonocle
+Version: 0.8
+Summary: A Python library for creating super fancy Unix daemons
+Home-page: http://github.com/jnrbsn/daemonocle
+Author: Jonathan Robson
+Author-email: jnrbsn at gmail.com
+License: MIT
+Description: daemonocle is a library for creating your own Unix-style daemons written in Python. It solves many
+        problems that other daemon libraries have and provides some really useful features you don't often
+        see in other daemons.
+        
+        .. contents:: **Table of Contents**
+          :backlinks: none
+        
+        Installation
+        ------------
+        
... 1244 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-daemonocle.git



More information about the Python-modules-commits mailing list