jnrbsn / daemonocle Goto Github PK
View Code? Open in Web Editor NEWA Python library for creating super fancy Unix daemons
License: MIT License
A Python library for creating super fancy Unix daemons
License: MIT License
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])
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)
?
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::
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.
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
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?
The example from the README fails:
user@host> python d.py
Traceback (most recent call last):
File "d.py", line 16, in <module>
daemon.do_action(sys.argv[1])
IndexError: list index out of range
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
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 ...
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 ?
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.
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
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)
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.
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.
Create examples folder with runnable scripts, the ones from the documentation.
Please add more usage examples.
Such as:
gunicorn myapp:app
but with daemonizing) or wsgiref (using any WSGI server).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?
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.
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.
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
.
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!
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?
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.
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 ?
Tons of bugs of psutil have been fixed since 2.1.1. See https://github.com/giampaolo/psutil/blob/master/HISTORY.rst
Could you update the requirement so that we use the latest psutil?
Same goes to click, the latest version of which is 3.3.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.