Coder Social home page Coder Social logo

daemonocle's People

Contributors

jnrbsn avatar sfisol avatar tingletech avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

daemonocle's Issues

using os.mkdir() crashes ERROR: Child exited immediately with exit code 127

I try to create log directory, while starting the job using os.mkdir() throws ERROR: Child exited immediately with exit code 127
the following code ...

def _config_logger():
    log_dir  = os.path.join(os.getcwd() ,"logs")
    if not os.path.exists( log_dir ):
         os.mkdir( log_dir )

    logfile  = os.path.join(log_dir ,"agent.log")

    logging.basicConfig(
        filename=logfile,
        level=logging.DEBUG, format='%(asctime)s [%(levelname)s] %(message)s',
    )
 ``
def main():
    config = _load_config()

    if config:
        _config_logger()
        logging.info('Daemon is starting')

        while True:
            print("akka")
            logging.debug('Still running')
            logging.warning('warning')
            time.sleep(config['pollIntervalSecs'])

if __name__ == '__main__':
    pidfile_name = 'kooo.pid'
    pidfile_path = os.path.join(os.getcwd() ,pidfile_name)
    daemon = MyDaemon(
        worker=main,
        pidfile=pidfile_path,
        detach=True,
    )
    daemon.do_action(sys.argv[1])

Add support immediate exit (without warning)

My daemon does terminate immediately if there is nothing to do.

Up to now this fails with the message "ERROR: Child exited immediately with exit code 0".

Is there a way to terminate immediately without creating an error message?

Maybe by doing sys.exit(100)?

Support for -h, --help or help is missing up to now

python d.py --help

Traceback (most recent call last):
  File "d.py", line 16, in <module>
    daemon.do_action(sys.argv[1])
  File "/home/guettli/projects/lala-env/lib/python3.8/site-packages/daemonocle/core.py", line 887, in do_action
    func = self.get_action(action)
  File "/home/guettli/projects/lala-env/lib/python3.8/site-packages/daemonocle/core.py", line 883, in get_action
    return get_action(self, action)
  File "/home/guettli/projects/lala-env/lib/python3.8/site-packages/daemonocle/core.py", line 56, in get_action
    raise DaemonError(
daemonocle.exceptions.DaemonError: Invalid action "--help"

I think -h, --help and help should be supported by the library.

Example fails for unclear reason

Example fails for unclear reason::

user@host> python d.py start

Starting d.py ... FAILED
ERROR: Child exited immediately with exit code 1

I guess that's because I start the daemon as user, not as root.

But I don't like to guess. I better error message would be great.

core.py import error on Windows Systems

though you catched the exception on calling resource functions,
you do a bare import of resource. But resource is not available on a Windows Pc...

Could you change

  import resource

to

  try:
    import resource
  except ImportError:
    None

Run binary inside daemonocle and intercept cli of that binary?

Is it possible to run a binary inside daemonocle and intercept its cli in daemonocle.
This binary is a C program which normally runs inside screen, or tmux and is the only way to send it to background.
So can I wrap this binary in daemonocle and cli intercept it?

Question about passing arguments

Hello, thank you for your project, is really awesome, it helped me big time :)

I was wondering which is the right way and if it possible to pass arbitrary arguments on the worker function.

More specifically, my problem is that I have a script and I want to read some parameters from a file. Then, depending on some user input I want to handle those parameters (from the file) either on the standard process of the script or start a daemon and pass those parameters on the daemon. Up until now, I am declaring those parameters on either a global variable or I create a class. Is there any other way?

Thanks

pytest is hanging on debian build pkg

I: pybuild base:184: cd /tmp/b/python-daemonocle/.pybuild/pythonX.Y_2.7/build; python2.7 -m pytest tests
============================= test session starts ==============================
platform linux2 -- Python 2.7.12rc1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /tmp/b/python-daemonocle, inifile:
collected 25 items

tests/test_actions.py ..
tests/test_basics.py ...

Could you provide example how to pas cli arguments for "main"

I would like to use some cli arguments in my app when starting as daemon mode.

The daemonocle.cli.DaemonCLI class also accepts a daemon_class argument that can be a subclass of daemonocle.Daemon.

this comment related to what I want, right? Could you provide some simple example about how to use this ?

debugging after os.fork() [python 3]

Hi,

I've almost got my daemon working under python 3. I wonder if you might have some advice on how to debug my last problem -- which I have created an isolated example of.

#!/usr/bin/env python
# filename: shove_daemonocle.py
import sys
import time
import logging

import daemonocle
from shove import Shove

def main():
    logging.basicConfig(
        filename='/tmp/daemonocle_example.log',
        level=logging.DEBUG, format='%(asctime)s [%(levelname)s] %(message)s',
    )
    logging.info('Daemon is starting')
    logging.debug('1')
    x = Shove()
    logging.debug('2')


def cb_shutdown(message, code):
    logging.info('Daemon is stopping')
    logging.debug(message)


if __name__ == '__main__':
    detach = False if len(sys.argv) > 2 else True
    daemon = daemonocle.Daemon(
        worker=main,
        detach=detach,
        shutdown_callback=cb_shutdown,
        pidfile='/tmp/daemonocle_example.pid',
    )
    daemon.do_action(sys.argv[1])

When I run this under python 3 and detach=True

$ ./shove_daemonocle.py start
Starting shove_daemonocle.py ... FAILED
ERROR: Child exited immediately with non-zero exit code 127
$ cat /tmp/daemonocle_example.log 
2014-06-20 23:36:09,900 [INFO] Daemon is starting
2014-06-20 23:36:09,901 [DEBUG] 1
2014-06-20 23:36:09,938 [INFO] Daemon is stopping
2014-06-20 23:36:09,938 [DEBUG] Dying due to unhandled RuntimeError: Failed to read 32 bytes from /dev/urandom

But when I run it detach=False

$ rm /tmp/daemonocle_example.log 
$ ./shove_daemonocle.py start no-detach
Starting shove_daemonocle.py ... OK
All children are gone. Parent is exiting...
$ cat /tmp/daemonocle_example.log 
2014-06-20 23:38:08,546 [INFO] Daemon is starting
2014-06-20 23:38:08,547 [DEBUG] 1
2014-06-20 23:38:08,583 [DEBUG] 2
2014-06-20 23:38:08,583 [INFO] Daemon is stopping
2014-06-20 23:38:08,583 [DEBUG] Shutting down normally

P.S. I love this module -- thanks for putting it together and merging the python 3 pull requests.

Allow actions to define their own CLI options

For more complex CLI cases, it'd be nice to be able to write:

class MyDaemon(daemonocle.Daemon):
    @daemonocle.expose_action
    @click.argument("filenames", nargs=-1, type=click.Path(exists=True))
    def do_thingy(self, filenames):
        pass

PID file permissions

Why not '644' here? Default file mode for open() is '777' but that's not quite right.
So could you change it?
Just self._pid_fd = os.open(self.pidfile, flags, mode=0o644)

How to let `do_action` return its result 'machine-readable' instead of writing it to `stdout`?

Looking at the source code, it appears to me that one can not control the verbosity of daemonocle (?). For instance, I am trying to check the status of a daemon from a python script. So far, my only option seems to be parsing the output captured from a sub-process via stdout. I'd love to be able to just call do_action, turn off any verbosity to stdout through an optional parameter and let it return a dict with detailed information instead.

I'd be willing to submit a pull request if this feature is of any interest.

Example (with click) fails with Python 3.6.2 on Linux

I have been trying to implement a piece of code using daemonocle, trying for hours to make it work ... It turns out that even your basic example (with click) does not work for me at all. The following code ...

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

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()

... will, when called as ./test.py start, always produce ...

Starting test.py ... FAILED
ERROR: Child exited immediately with exit code 1

... after about 1 sec (which is the default wait time of your system for checking whether the daemon is alive or not). Initially, I tried to make my daemon at least log some "hello world" messages (with the logging module), but did not get beyond producing some "1" exit codes, a lot of "0" exit codes and quite a few "127" exit codes.

I am running CPython 3.6.2 in a virtual environment on top of openSUSE Leap 42.3 (kernel 4.4.87, glibc 2.22). Any hints on how to debug this are greatly appreciated.

Add more examples

Create examples folder with runnable scripts, the ones from the documentation.
Please add more usage examples.

Such as:

  • Using threading and how-to cleanly and safely stop the program.
  • Using multiprosessing and how-to cleanly and safely stop the program.
  • How-to handle file reloading with Flask and how-to cleanly and safely stop the program.
  • WSGI: such as gunicorn (functionality like gunicorn myapp:app but with daemonizing) or wsgiref (using any WSGI server).
  • Show an example with setproctitle.
  • Show how-to stop the daemon from inside the worker function.

I ask about these examples mainly because I do not know how-to cleanly and safely stop a threaded server that uses serve_forever. How do you send a stop signal to such a server? How do you do it safely and with predictable results?

Kill daemon if it's not going down gracefully

In stop action it tries to terminate process with SIGTERM and if it fails just shows a message, but sometimes daemons aren't peaceful, might not even listen to signals or busy with their evil actions so we have to use force to get rid of them.
I just wanted to go with some sort of another try except block with SIGKILL but I thought I might not keep up with style and other stuff, would you add it please?

Thanks.

Python 3.8: Socket operation on non-socket

I am seeing the following traceback in CPython 3.8:

  File "/project/env383/bin/yabs", line 33, in <module>
    sys.exit(load_entry_point('yabs', 'console_scripts', 'yabs')())
  File "/project/env383/bin/yabs", line 25, in importlib_load_entry_point
    return next(matches).load()
  File "/home/ernst/Desktop/SOFTWARE/_CPYTHON/3.8.3/target/lib/python3.8/importlib/metadata.py", line 77, in load
    module = import_module(match.group('module'))
  File "/home/ernst/Desktop/SOFTWARE/_CPYTHON/3.8.3/target/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 783, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/project/github.yabs/src/yabs/__init__.py", line 3, in <module>
    from .cli import (
  File "/project/github.yabs/src/yabs/cli.py", line 78, in <module>
    def server():
  File "/project/env383/lib/python3.8/site-packages/click/core.py", line 1362, in decorator
    cmd = command(*args, **kwargs)(f)
  File "/project/env383/lib/python3.8/site-packages/click/decorators.py", line 130, in decorator
    cmd = _make_command(f, name, attrs, cls)
  File "/project/env383/lib/python3.8/site-packages/click/decorators.py", line 98, in _make_command
    return cls(
  File "/project/env383/lib/python3.8/site-packages/daemonocle/cli.py", line 32, in __init__
    context_settings = {'obj': self.daemon_class(**self.daemon_params)}
  File "/project/env383/lib/python3.8/site-packages/daemonocle/core.py", line 37, in __init__
    self.detach = detach & self._is_detach_necessary()
  File "/project/env383/lib/python3.8/site-packages/daemonocle/core.py", line 258, in _is_detach_necessary
    if cls._is_socket(sys.stdin):
  File "/project/env383/lib/python3.8/site-packages/daemonocle/core.py", line 224, in _is_socket
    sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_RAW)
  File "/home/ernst/Desktop/SOFTWARE/_CPYTHON/3.8.3/target/lib/python3.8/socket.py", line 544, in fromfd
    return socket(family, type, proto, nfd)
  File "/home/ernst/Desktop/SOFTWARE/_CPYTHON/3.8.3/target/lib/python3.8/socket.py", line 231, in __init__
    _socket.socket.__init__(self, family, type, proto, fileno)
OSError: [Errno 88] Socket operation on non-socket

It looks similar to CPython issue 39685. Also see PR #24 - it appears to fix the issue.

Integration with systemd

I think it would be very nice to have an example on how to deploy a deamonocle daemon with systemd. Said differently, how to write a foo.service that works with daemonocle.

PID file deleted but process not terminated

What happens to me on every second or third restart of my process is that Daemonocle claims the process was not running, deletes the PID file, and starts it again. This fails because, in fact, the process was still running, and it binds to a port so the second instance crashes quickly when it can’t bind to the port.

My fix has been to determine the PID (with ps), echo it back into the PID file, and try again. On the second try it usually or always succeeds.

telofy@nyx ~/c/lexicockpit (master)> ../lexicockpit/bin/server restart
WARNING: lexicockpit.wsgi is not running
Starting lexicockpit.wsgi ... OK
telofy@nyx ~/c/lexicockpit (master)> ps aux | grep lexico
telofy    8266  0.0  0.2 136940 32948 ?        S    17:26   0:00 /usr/bin/python3.4 ../lexicockpit/bin/server restart
telofy    8772  0.0  0.0  12732  2300 pts/0    S+   17:27   0:00 grep --color=auto lexico
telofy   16547  0.0  0.2 136940 33212 ?        S    16:29   0:00 /usr/bin/python3.4 ../lexicockpit/bin/server restart
telofy@nyx ~/c/lexicockpit (master)> echo 8266 > daemonocle.pid
telofy@nyx ~/c/lexicockpit (master)> ../lexicockpit/bin/server restart
Stopping lexicockpit.wsgi ... OK
Starting lexicockpit.wsgi ... OK

The process is a Python 3.4 Django application run by Gunicorn on a Debian-based system (Linux nyx 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u1 (2016-09-03) x86_64 GNU/Linux).

The Daemonocle invocation looks like this:

daemon = daemonocle.Daemon(
    worker=StandaloneApplication(application, settings.GUNICORN_SETTINGS).run,
    workdir='.',
    prog=__name__,
    pidfile='daemonocle.pid')
daemon.do_action(sys.argv[1])

Thank you!

Worker with subprocess

I'm trying to build a function that can execute a command as a daemon using daemonocle. A simplified version looks a bit like

@click.command()
@click.argument(
    "ACTION",
    type=click.Choice(
        [
            "start",
            "stop",
            "restart",
            "status",
            "debug",
        ]
    ),
)
@click.argument("NAME", type=str)
@click.argument("COMMAND", type=str, nargs=-1, required=False)
def daemonize(
    action: str,
    name: str,
    command: str | None = None,
):
    """Runs a command as a daemon."""

    def worker():

        if command is None:
            return

        subprocess.run(
            " ".join(command),
            shell=True,
            capture_output=False,
            cwd=os.getcwd(),
        )

    pid_file = f"/var/tmp/{name}.pid"

    if action == "debug":
        worker()
    else:
        daemon = Daemon(worker=worker, pid_file=pid_file)
        daemon.do_action(action)

When I try to run this with a test script that blocks for a long time, the daemon fails with error ERROR: Child exited immediately with exit code 0. I think this is somehow due to subprocess spawning a child process and the parent terminating, but I've tried several approaches, including forking, os.waitpid(), etc and have had no luck. Any suggestions about how to use subprocess in a worker?

pidfile

pidfile and write issues (non-root)

When you want the daemon to write it's pidfile to /var/run obviously you need to be root.

When starting the daemon as root and changing the process uid/gid, I still ran into the pidfile issue, regarding write permissons.

Working fine if ...

Looking into the code I found that if the pidfile contains an additional directory, like:
/var/run/MyDaemon/MyDaemon.pid that it will create the directory and the pidfile with the ownership reflecting uid and gid set.

Maybe a small add-on to the docs ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.