I've written a simple Python class for creating daemons on unix/linux systems. It was pieced together for various other examples, mostly corrections to various Python Cookbook articles and a couple of examples posted to the Python mailing lists. It has support for a pidfile to keep track of the process. I hope it's useful to someone.
Below is the Daemon class. To use it, simply subclass it and implement the run() method. Download this file.
Update 2009-05-31: An anonymous contributor has written a version of the Daemon class suitable for Python 3.x. Download the Python 3.x version here. The code below is for Python 2.x
- #!/usr/bin/env python
- import sys, os, time, atexit
- from signal import SIGTERM
- class Daemon:
- """
- A generic daemon class.
- Usage: subclass the Daemon class and override the run() method
- """
- def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
- self.stdin = stdin
- self.stdout = stdout
- self.stderr = stderr
- self.pidfile = pidfile
- def daemonize(self):
- """
- do the UNIX double-fork magic, see Stevens' "Advanced
- Programming in the UNIX Environment" for details (ISBN 0201563177)
- http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
- """
- try:
- pid = os.fork()
- if pid > 0:
- # exit first parent
- sys.exit(0)
- except OSError, e:
- sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
- sys.exit(1)
- # decouple from parent environment
- os.chdir("/")
- os.setsid()
- os.umask(0)
- # do second fork
- try:
- pid = os.fork()
- if pid > 0:
- # exit from second parent
- sys.exit(0)
- except OSError, e:
- sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
- sys.exit(1)
- # redirect standard file descriptors
- sys.stdout.flush()
- sys.stderr.flush()
- si = file(self.stdin, 'r')
- so = file(self.stdout, 'a+')
- se = file(self.stderr, 'a+', 0)
- os.dup2(si.fileno(), sys.stdin.fileno())
- os.dup2(so.fileno(), sys.stdout.fileno())
- os.dup2(se.fileno(), sys.stderr.fileno())
- # write pidfile
- atexit.register(self.delpid)
- pid = str(os.getpid())
- file(self.pidfile,'w+').write("%s\n" % pid)
- def delpid(self):
- os.remove(self.pidfile)
- def start(self):
- """
- Start the daemon
- """
- # Check for a pidfile to see if the daemon already runs
- try:
- pf = file(self.pidfile,'r')
- pid = int(pf.read().strip())
- pf.close()
- except IOError:
- pid = None
- if pid:
- message = "pidfile %s already exist. Daemon already running?\n"
- sys.stderr.write(message % self.pidfile)
- sys.exit(1)
- # Start the daemon
- self.daemonize()
- self.run()
- def stop(self):
- """
- Stop the daemon
- """
- # Get the pid from the pidfile
- try:
- pf = file(self.pidfile,'r')
- pid = int(pf.read().strip())
- pf.close()
- except IOError:
- pid = None
- if not pid:
- message = "pidfile %s does not exist. Daemon not running?\n"
- sys.stderr.write(message % self.pidfile)
- return # not an error in a restart
- # Try killing the daemon process
- try:
- while 1:
- os.kill(pid, SIGTERM)
- time.sleep(0.1)
- except OSError, err:
- err = str(err)
- if err.find("No such process") > 0:
- if os.path.exists(self.pidfile):
- os.remove(self.pidfile)
- else:
- print str(err)
- sys.exit(1)
- def restart(self):
- """
- Restart the daemon
- """
- self.stop()
- self.start()
- def run(self):
- """
- You should override this method when you subclass Daemon. It will be called after the process has been
- daemonized by start() or restart().
- """
And here is an example implementation. It implements the daemon as well as it's controlling client. Simply invoke this script with start, stop or restart as it's first argument. Download this file.
- #!/usr/bin/env python
- import sys, time
- from daemon import Daemon
- class MyDaemon(Daemon):
- def run(self):
- while True:
- time.sleep(1)
- if __name__ == "__main__":
- daemon = MyDaemon('/tmp/daemon-example.pid')
- if len(sys.argv) == 2:
- if 'start' == sys.argv[1]:
- daemon.start()
- elif 'stop' == sys.argv[1]:
- daemon.stop()
- elif 'restart' == sys.argv[1]:
- daemon.restart()
- else:
- print "Unknown command"
- sys.exit(2)
- sys.exit(0)
- else:
- print "usage: %s start|stop|restart" % sys.argv[0]
- sys.exit(2)
That's it! I hope this is of some use to someone. Happy coding!
Comments
#1 Guido van Steen
#2 coolluck (http://tech.coolluck.org/)
I think it'll be better add checking pidfile existance
because atexit handler may delete pidfile before execute os.remove(self.pidfile) in exception Handler "except OSError, err"
...
except OSError, err:
err = str(err)
if err.find("No such process") > 0:
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
...
#3 Sander Marechal (http://www.jejik.com)
#4 narthollis
And far more elegant than my previous solution.
Many Thanks :)
#5 Anonymous Coward
#6 Sander Marechal (http://www.jejik.com)
This is really basic stuff and not very original. It's Public Domain, so do with it as you please.
#7 Jacob Singh (http://pajamadesign.com)
I've got it working, but I have one problem. I'm trying to do some stuff before exiting. So, in my code:
signal.signal(signal.SIGTEM,myhandler)
def myhandler(signum,frame):
#do something
sys.exit()
I assume that my sys.exit is calling itself by raising a SIGTERM somehow which is really annoying. How can I stop this?
Thanks!
Jacob
#8 Sander Marechal (http://www.jejik.com)
So, add the stuff you want to do before shutdown to the self.delpid() function.
#9 Anonymous Coward
# redirect standard file descriptors
#sys.stdout.flush()
#sys.stderr.flush()
#si = file(self.stdin, 'r')
#so = file(self.stdout, 'a+')
#se = file(self.stderr, 'a+', 0)
#os.dup2(si.fileno(), sys.stdin.fileno())
#os.dup2(so.fileno(), sys.stdout.fileno())
#os.dup2(se.fileno(), sys.stderr.fileno())
any idea?
thx
#10 Sander Marechal (http://www.jejik.com)
#11 Anonymous Coward
#12 Sander Marechal (http://www.jejik.com)
Can you tell me what os.path.devnull is set to in Python on OSX?
#13 Preston Hunt (http://prestonhunt.com)
#14 Guilherme Gall
Something like that:
def status(self):
try:
pf = file(self.pidfile, 'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None
try:
procfile = file("/proc/%d/status" % pid, 'r')
procfile.close()
except IOError:
sys.stdout.write("there is not a process with the PID specified in %s\n" % self.pidfile)
sys.exit(0)
except TypeError:
sys.stdout.write("pidfile %s does not exist\n" % self.pidfile)
sys.exit(0)
sys.stdout.write("the process with the PID %d is running\n" % pid)
#15 Jonathan Manning
if (hasattr(os, "devnull")):
DEVNULL = os.devnull
else:
DEVNULL = "/dev/null"
Then use DEVNULL instead of the string "/dev/null" in the default arguments.
~J
#16 HosipLan (http://kdyby.org)
#17 Raj (http://rajorshi.net/blog)
#18 Anonymous Coward
def run(self):
while True:
print "test1\n"
time.sleep(1)
This does not log anything in the log file specified in the constructor of Daemon. If I remove the sleep(1) call, it works. I was thinking of a buffering issue but removing the buffering to stdout in daemon.py did not change anything.
Any idea ?
#19 Sander Marechal (http://www.jejik.com)
A far better alternative however is to use the "logging" module instead.
#20 Anonymous Coward
I tried replacing the print statement with logging.info("Test"). This has the same buffer issue as print statement. Can you explain why you redirect in your code stdout if it cannot be used reliably for output ? For example, when the daemon is stopped, there is no flush or close in the stop function and information that was sent to the log file is lost.
#21 Sander Marechal (http://www.jejik.com)
Using stdout and flush() can sorta work, but you don't have a real daemon anymore. Consider this. Open a terminal, start your program and then close the terminal. What happens to stdout now? It's gone. That's why it needs to be redirected to /dev/null. And that's why all daemons use logfiles or log to the syslog.
#22 Vik
I have a question, I need to start some scripts and stop them when I want and would also like to know their status, I have attached to this daemon, but then when I am starting the daemon, in ps -aux only the daemon is shown, not that those scripts have started. Or maybe I am going in the wrong way... Can someone help me?
#23 Sander Marechal (http://www.jejik.com)
#24 Roel
#25 Sander Marechal (http://www.jejik.com)
#26 Andr
When I extract this class to a submodule it does not work. It seems that the wrong process is terminated after the first fork...
Here is my modulcode... Help would really be appriciated...
#27 Andr
just stupid me forget to import a module required by the overriding run method...
#28 Sander Marechal (http://www.jejik.com)
#29 Andre
#30 Brian
#31 Robert
#32 Sander Marechal (http://www.jejik.com)
@Robert: That sounds like a great project. I always like hearing where my code ends up :-)
#33 Brian
Thanks for the very useful code! I'm using it to implement an IRC bot. Works great.
#34 Vik
close failed: [Errno 10] No child processes
I am not sure as where I am going wrong, when I looked up on google to find out that this might be a bug in python:
http://mail.python.org/pipermail/python-bugs-list/2007-August/039194.html
I wanna keep my logs and get rid of this error, the problem is the error is continuously writing to a file and that way in a certain period of time my hard drive will be full with just one text file.
Please let me know if anyone has ever faced this error. Any help is appreciated.
Thanks
Vik
#35 Anonymous Coward
"""Generic linux daemon base class for python 3.x."""
import sys, os, time, atexit, signal
class daemon:
"""A generic daemon class.
Usage: subclass the daemon class and override the run() method."""
def __init__(self, pidfile): self.pidfile = pidfile
def daemonize(self):
"""Deamonize class. UNIX double fork mechanism."""
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError as err:
sys.stderr.write('fork #1 failed: {0}\n'.format(err))
sys.exit(1)
# decouple from parent environment
os.chdir('/')
os.setsid()
os.umask(0)
# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
sys.exit(0)
except OSError as err:
sys.stderr.write('fork #2 failed: {0}\n'.format(err))
sys.exit(1)
# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = open(os.devnull, 'r')
so = open(os.devnull, 'a+')
se = open(os.devnull, 'a+')
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
# write pidfile
atexit.register(self.delpid)
pid = str(os.getpid())
with open(self.pidfile,'w+') as f:
f.write(pid + '\n')
def delpid(self):
os.remove(self.pidfile)
def start(self):
"""Start the daemon."""
# Check for a pidfile to see if the daemon already runs
try:
with open(self.pidfile,'r') as pf:
pid = int(pf.read().strip())
except IOError:
pid = None
if pid:
message = "pidfile {0} already exist. " + \
"Daemon already running?\n"
sys.stderr.write(message.format(self.pidfile))
sys.exit(1)
# Start the daemon
self.daemonize()
self.run()
def stop(self):
"""Stop the daemon."""
# Get the pid from the pidfile
try:
with open(self.pidfile,'r') as pf:
pid = int(pf.read().strip())
except IOError:
pid = None
if not pid:
message = "pidfile {0} does not exist. " + \
"Daemon not running?\n"
sys.stderr.write(message.format(self.pidfile))
return # not an error in a restart
# Try killing the daemon process
try:
while 1:
os.kill(pid, signal.SIGTERM)
time.sleep(0.1)
except OSError as err:
e = str(err.args)
if e.find("No such process") > 0:
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
print (str(err.args))
sys.exit(1)
def restart(self):
"""Restart the daemon."""
self.stop()
self.start()
def run(self):
"""You should override this method when you subclass Daemon.
It will be called after the process has been daemonized by
start() or restart()."""
#36 Sander Marechal (http://www.jejik.com)
I suggest you look at the backtraces for your error and see where they originate. Then simply catch the OSError and act appropriately (i.e. assume the thread has died, clean up and restart it for example).
#37 Sander Marechal (http://www.jejik.com)
#38 Vik
#39 Sander Marechal (http://www.jejik.com)
The first poster had a problem implementing his own daemon. He was implementing his code after the run() function. The answer is that your code should replace the run() function. That is what overriding a function means. You create your own function that replaces the original. You should make sure that the run() function never exits. That is why the example code has an infinite loop in it. If the run() function ever exits then the daemon stops.
The second poster had a question about the pidfile. IIRC he had a problem under Python 2.4 that the PID of the first fork was written to the pidfile and not the PID from the second fork, the one that keeps running. If I get this wrong, please re-post and I promise I will press the "ham" button this time :-)
Anyway, I have no idea what would cause this. I have tested this daemon code in 2.4, 2.5 and 2.6 and it works fine for me. The code that reads the pid and created the pidfile happens after the second fork. The original process and the first fork should already be dead by the time the pidfile is written.
It may be possible that there is a bug in the 2.4 version of os.getpid() but that is pure speculation. I know of no such bug, but one hypothetical scenario is that the second fork reaches os.getpid() before the first fork has exited completely (remember, forks run in parrallel). You could try a simple time.sleep(1) after the second fork but before calling the os.getpid() function. That sleep will make sure that the first fork is dead by the time the pidfile is created.
#40 Justin
The issue I was wondering about is that the pid of the daemon is the same as the second parent's pid--that's what's actually running, and that's what's in pidfile. To see what I'm seeing, add 'print pid' after each occurrence of 'if pid > 0:' in daemonize(), just before 'sys.exit()'. If I'm understanding correctly, those should be the pids of the first and second parents, while the second child's pid is obtained further on with a call to 'os.getpid()'. In my environment, python 2.4 on CentOS 5.3, the second child's pid is the same as the second parent's pid.
It's not really a problem, but I'm obviously not getting something here. I thought the process went like this: first parent->fork->first child/second parent->fork->second child. So there should be three pids in all.
The purpose of the second fork is to make sure that the daemon isn't the process group leader of the new session, but if the second fork isn't taking a new pid, then it's still the process group leader, yes?
#41 Sander Marechal (http://www.jejik.com)
The fork() command returns 0 in the child and returns the child's pid in the parent. So, the value of pid that you are printing just after 'if pid > 0:' is the pid of the child, not the pid of the parent. You are printing the pid of the first child and second child, not of the parent and first child.
You can see that by leaving those print statements in and adding a 'print os.getpid()' all the way at the beginning of the daemonize() method, before the first fork. Now you should see three different pid's printed. The original parent, the first child and the second child.
#42 Seth
daemon.py:
I also wrote an improvised test file for this file (still ugly, but does the job), test_daemon.py:
#43 Vik
#44 Sander Marechal (http://www.jejik.com)
#45 Vik
#46 acid (http://blutrache.blogspot.com)
# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = file(self.stdin, 'r')
so = file(self.stdout, 'a+')
se = file(self.stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
# write pidfile
atexit.register(self.delpid)
pid = str(os.getpid())
file(self.pidfile,'w+').write("%s\n" % pid)
#47 Sander Marechal (http://www.jejik.com)
#48 acid (http://blutrache.blogspot.com)
#49 Sander Marechal (http://www.jejik.com)
#50 Doug
"Note: the functions registered via this module are not called when the program is killed by a signal, when a Python fatal internal error is detected, or when os._exit() is called."
If you step through the code you'll see that the function is never called.
So, is there any way to get some cleanup function to run when Daemon.stop() is called?
#51 Sander Marechal (http://www.jejik.com)
Anyway, one workaround would be to trap the SIGTERM in the daemon and call a clean sys.exit() so that the atexit function does work.
#52 Doug
try:
while 1:
os.kill(pid, SIGTERM)
time.sleep(0.1)
except OSError, err:
err = str(err)
if err.find("No such process") > 0:
os.remove(self.pidfile)
else:
print str(err)
sys.exit(1)
Can you give an example of how to trap the SIGTERM? I can't seem to get it to work. Thanks for this writeup by the way, I use it all the time!
#53 Doug
#54 Chenix
1. does a daemon needs to have a user attached to it in some way, so it gets the user's
access policy for itself too?
2. what would be a good practice for a disk location of application files designed to
run as a daemon? (/usr/local maybe?)
3. putting all this together, lets say my python application files and some data files
are located under /usr/local/myapp, what steps do i have to take in order that my daemon
will be able to access this location?
thanks
#55 Sander Marechal (http://www.jejik.com)
A daemon is no different from a regular application. Application files should be in the same place (/usr or /usr/local). Privileges work the same. The only thing that is different about a daemon is that you get your terminal back after starting it :-)
#56 Mike
So I got the script working and all, after starting the daemon I can see (and hear) that the song is playing. The problem is that it doesn't stop playing when I stop the daemon. I modified the delpid() method:
...
def delpid(self):
os.system('mpc stop')
os.remove(self.pidfile)
...
but somehow the command "os.system('mpc stop')" doesn't run. The "mpc" manual is very simple and I know that "mpc stop" works fine outside of the script. Any idea what I might be doing wrong? The script runs as root and everything else works perfectly (up to now :)
#57 Sander Marechal (http://www.jejik.com)
Instead, try sending a signal to MPD. You need to know it's process ID (pid) though. Example:
#58 Mike
Hum the indentation didn't come right on my last post.
#59 Sander Marechal (http://www.jejik.com)
If you are terminating the daemon from within (e.g. based on serial port communication) you could use sys.exit() instead of Daemon.stop(). That way the atexit() will fire and execute delpid().
#60 Mike
#61 Seth
#62 Sander Marechal (http://www.jejik.com)
#63 stelvis
couple of questions:
regarding Seth's post on using signal handlers to get cleaner exit behaviour - any chance of any elaboration on how that should work? (sorry if I'm missing the obvious)- eg I assume the def is another method declared in the Daemon parent class, but where exactly is the signal stuff called from? does it replace the stop method?
secondly I have been trying to get logging to work, and seem to have a working model but it ONLY works if i call the run() method directly (I implemented a 'debug' or 'foreground' mode as you suggested above) - if run() is called from start() after self.daemonize() the logging stuff just hangs the daemon (ie no PID file is created, run() isn't called)
code is below:
class SymServer(Daemon):
def run(self):
#logging.config.fileConfig("SymServer_logging.conf")
#logger = logging.getLogger("SymServer")
#create socket
s = socket(AF_INET, SOCK_STREAM) # create a TCP socket
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # don't wait for port to be releaed
s.bind((myHost, myPort)) # bind it to the server
s.listen(5) # allow 5 simultaneous pending connections
#logger.info("server starting on port: %d" % (myPort))
# listen for clients
while 1:
connection, address = s.accept() # connection is a new
while 1:
data = connection.recv(1024) # receive up to 1K bytes
if data:
connection.send('echo -> ' + data)
#logger.info("echoing: " + data)
else:
#logger.info("Client exiting")
break
connection.close() # close socket
(the actual symlinking stuff will eventually replace the simple echo stuff there currently)
#64 stelvis
:)
#65 Sander Marechal (http://www.jejik.com)
#66 stelvis
actually the log file was being directed to /home/%user%/python/symserver/symserver.log anyway and I did make sure it had write permissions...as soon as I stopped using a seperate logging.config file it worked fine.
BUT
the logging conf file (which was also in that dir) didn't have an explicit path set (so your right in a way i think) - it just wasn't finding the config file
cheers
#67 Sander Marechal (http://www.jejik.com)
#68 dik123
For me this code:
# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = file(self.stdin, 'r')
so = file(self.stdout, 'a+')
se = file(self.stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
Dose not work for pythons 'print'
But this code works:
# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
sys.stdout = file(self.stdout, 'a+')
sys.stderr = file(self.stderr, 'a+', 0)
si = file(self.stdin, 'r')
os.dup2(si.fileno(), sys.stdin.fileno())
#69 prakash
and my code is giving me trouble.This process is not starting(i checked using ps) .What i observed is if i remove all those file descriptors the code works.But it should work with those .Also i made sure that the directory structure is correct.so can someone plz sort this out
#70 Sander Marechal (http://www.jejik.com)
#71 Peter (http://sourceforge.net/projects/cozy/)
Following up on the discussion on exiting the daemon, I wondered which signal it receives if I log out. It seems like it's not a SIGTERM. I tried the SIGHUP, but it doesn't work either. So whenever I log out and log in (it's in the autostart), it doesn't start because the pid-file already exists. Note that everything's fine if I restart the complete machine. Any hints?
#72 solarn
signal.signal(signal.SIGTERM, self.delpid)
atexit.register(self.delpid)
[....]
def delpid(self):
os.remove(self.pidfile)
self.cleanup()
I also added a call to self.cleanup(), to simplify customisations even more by allowing the user to override cleanup(), without having to touch delpid() (and perhaps the risk of forgetting to remove the pidfile?)
#73 solarn
#74 solarn
Smal misstake in prev. post:
signal.signal(signal.SIGTERM, self.delpid)
atexit.register(self.delpid)
should instead be:
def cleanup_handler(signum, frame):
sys.exit(0)
signal.signal(signal.SIGTERM, cleanup_handler)
atexit.register(self.delpid)
Now, whenever a SIGTERM is caught, sys.exit() is called and atexit should kick in and cleanup.
#75 Sander Marechal (http://www.jejik.com)
@Solarn: I'll see if I have time to update the article in the coming few days. I've just moved so I have been a bit busy paiting, redecorating, shopping for furniture and yelling at my ISP for the low quality ADSL connection I get at my new house.
#76 eromirou
first of all, thanks a lot for this code, it was really helpful.
I'm having a weird problem...
I'm using '/var/log/mydaemon.log' and '/var/log/mydaemon.err' as stdout and stderr respectively, but I'm not getting anything on those files unless I print something before redirecting the output...
When I print something before redirecting, it goes to the terminal, the daemon goes in the background, and then anything that's printed during execution goes into the files I stated.
Any ideas on what might be causing this behaviour?
Thanks
#77 Girish Venkatachalam (http://spam-cheetah.com)
Can you please explain the need for the Pid file and sleep(2)?
Without that it would be perfect I think.
Great work. Keep going!
Ever yours,
Girish
#78 Sander Marechal (http://www.jejik.com)
@Girish: After the daemon has started you still need to communicate with it from the outside. For example, in order to stop it. To do that you need to know the process ID, which is stored in the pidfile. The pidfile also acts as a lockfile, preventing multiple instances of the daemon running.
I don't see any sleep(2) in the code. Which sleep do you mean?
#79 eromirou
I made stdout unbuffered like so:
sys.stdout = file(self.stdout, 'a+', 0)
Do you see any problems with this?
Thanks
#80 Sander Marechal (http://www.jejik.com)
#81 Monte Davis
I'm using this code to daemonize a number of different business processes that we have. It works very well and very cleanly. I have however run into a little problem.
I want to start and stop the daemon from a web-interface using django. I save a django object and on save I run the command(python daemon-file-name start or python daemon-file-name stop accordingly).
The stop works fine. However, the start results in the web page never "hanging". The process actually starts but I find it listening on port 80.
I have found in a forum someone who had a similar issue in Python Win32. The link is here -
http://mail.python.org/pipermail/python-win32/2005-May/003310.html
It seems that I need to close stdout in order to return control to the webserver and not inherit the handles of the process that launches the daemon.
This is consistent with some other comments that I have found on the web.
In this other daemon code,
http://code.activestate.com/recipes/278731/
os.close(1) and os.close(2) are called as are the sys.stdout.close()
Here is another incomplete post that deals with similar issues --
http://code.activestate.com/recipes/186101/
I have tried to add these lines in a number of places in your code but nothing works. Either the daemon doesn't start from the command line or the daemon does not release when called from the webserver.
Any help here would be very appreciated.
Thanks
Monte
#82 Sander Marechal (http://www.jejik.com)
Note: I have not tested the above code. I don't know Django. If this does not work, please tell me how Django runs external scripts. Does it use subprocess.Popen?
#83 Megaman821
#84 Sander Marechal (http://www.jejik.com)
#85 Adam Collard
#86 CMFL
This was written in python 2.6. I am not sure if it will work with python 3.
To use this, you can either fork this script to the background or open another terminal and send the signals. The defined signals are SIGTERM (kill -15) and SIGINT (kill -2) -> CTRL-C. If you type CTRL-C on your keyboard and this script is not forked to the backgournd you will see that the class handled the SIGINT signal correctly.
Here is the example not forking script to the background and issuing a CTRL-C in the terminal the script was run from.
Here is an example of the script being forked to the background, and then sending a kill command to the running proccess.
#87 Sander Marechal (http://www.jejik.com)
#88 CMFL
#89 Anonymous Coward
#90 Sander Marechal (http://www.jejik.com)
#91 Batista
#92 Alfredo
#93 Josh R
#94 Anonymous Coward
#95 Vindicar
I'm just too new to *nix. =[
#96 haridsv
#97 thcourbon (http://blog.cafeaumiel.com)
#98 Senton
#99 James (http://linux-101.org)
@Seth and @CMFL - Fantastic contributions. Thank you both.
#100 J_Skrilla
#101 Anonymous Coward
super(MyClass, self).__init__()
.. you might want to make Deamon inherit from object so that it works.
great work everyone.. very useful
#102 Anonymous Coward
#103 Sander Marechal (http://www.jejik.com)
#104 Rico (http://www.rodaddys.com)
I do know that I get the proper pid from the os.fork, then when it trys to do tyhe sys.exit(0) it fails, and actually exits the whole app, but I do not get the error that "fork #1 failed...."
Any Ideas?
Rico
#105 Sander Marechal (http://www.jejik.com)
#106 Greggory Hernandez (http://www.icount.com)
The only problem I'm having is when I set stderr and stdout to be two different files (just not /dev/null), and then from the EventHandler class I call sys.stderr.write('test') and sys.stdout.write('test'), 'test' only gets written to stderr, and not stdout.
Any thoughts on this? That'd be a big help.
Thanks again!
#107 Sander Marechal (http://www.jejik.com)
#108 Andreas
This is how I have it now in daemon-example.py:
but the daemon keeps exiting when it is started. Could you give me an example which writes something to an file or something similar?
#109 Sander Marechal (http://www.jejik.com)
#110 Andreas
Now I have rewrote it and it works great. =)
#111 olavgg
51 print 0.5
52 os.dup2(si.fileno(), sys.stdin.fileno())
53 print 0.7
54 try:
55 print so.fileno()
56 print sys.stdout.fileno()
57 os.dup2(so.fileno(), sys.stdout.fileno())
58 except OSError, e:
59 print str(e)
60 print 0.8
61 os.dup2(se.fileno(), sys.stderr.fileno())
62 print 1.2
</code
The code above gives the following output
0.5
0.7
6
1
It seems like it just dies for a weird reason running os.dup2(so.fileno(), sys.stdout.fileno())
I use Python2.7 and FreeBSD-8.1 Release
#112 Sander Marechal (http://www.jejik.com)
Alternatively, you could try to comment out the double fork to keep it in the foreground. See if any exceptions crop up. If they do, fix them and the uncomment the double fork again.
#113 Ryan (http://www.ryanbrady.org)
#114 chzealot (http://blog.losthit.com)
I think it's better to check the pid to see if the process really exists
such as (OS X or Linux)
if pid:
try:
os.kill(pid, 0)
except OSError:
pid = None
#115 Sam Thomson
As it is, when you daemonize, the parent is killed and the child takes over. So if you do anything in your main program after daemonizing, it gets done by the child.
E.g. in
the second daemon is spawned BY the first daemon, and doesn't start until after the first daemon finishes.
What I actually want to do is fork off a daemon then continue with normal operation WHILE the daemon is running. I.e. those two daemons should run simultaneously, and you should see the print statements because they should come from the main thread.
Here's a patch that behaves more like I would expect:
#116 Sander Marechal (http://www.jejik.com)
#117 Jill
I'm sure it would be much appreciated if you find the time to combine everything into Daemon v2.0. For me, it would be great to be able to compare with what I have done.
#118 kaliko
But I don't get the while loop over os.kill(pid, SIGTERM) (line 106). If the process is not shuting down after the first SIGTERM it is usually because the soft is stuck and only a SIGKILL would stop it (that's what my experience in *nix administration tells me, I might be wrong).
And because the exception caught right after is redundant with Daemon().delpid() I'm willing to remove this bloc of code.
Could you explain your choice?
k.
#119 Sander Marechal (http://www.jejik.com)
In theory you could send a single SIGTERM and then loop over a 0 (zero) signal, waiting for the daemon to exit.
#120 PoTe
I see lots of comments, and lots of people submitting new features for this - increasingly less so - simple daemon. I think you should publish it on github, that way we can all make our contributions and push them to you. I know it's not supposed to be a big thing, but it is a good solution for problems that require a lightweight daemon on them instead of something big and cumbersome like twisted. What do you think?
#121 Sander Marechal (http://www.jejik.com)
#122 Francisco Ram rez
>How do you interact with the deamon after starting it? I mean, after calling "python <daemonname.py> start". If you want to stop it. How do you access to it? Because if you call "python <daemonname.py> stop" you are dealing with a new instance, doesn't it?
#123 Sander Marechal (http://www.jejik.com)
#124 Francisco Ramirez
#125 Francisco Ramirez
I am launching two threads in the run method of the daemon. I would like to access to them after in other command (status, for example). Is there any way to recover the data of the process from its pid?
#126 Francisco Ramirez
#127 Sander Marechal (http://www.jejik.com)
As for file access, remember that the current working directory of a daemon is the filesystem root (/), so use full paths.
#128 Hammy Havoc (http://www.hammyhavoc.com)
#129 Strae
if os.path.exists(self.pidfile:
shuld be
if os.path.exists(self.pidfile):
Thanks for sharing, great article!
#130 Sander Marechal (http://www.jejik.com)
#131 Mike Fuzzy Partin
#132 David Underhill (http://www.dound.com)
#133 Jan de Jager (http://www.bleepsquare.co.za)
#134 John Randall
--- a/daemon.py 2011-06-21 14:39:30.783947588 +0200
+++ b/daemon.py 2011-06-21 14:38:37.895947562 +0200
@@ -107,7 +107,8 @@ class Daemon:
os.kill(pid, SIGTERM)
time.sleep(0.1)
except OSError, err:
- if err.errno == 3:
+ err = str(err)
+ if err.find("No such process") > 0:
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
#135 computerquip
#136 Justin Barber (https://github.com/barberj/Saerpent)
#137 Anonymous Coward
I found it more useful to kill the pid file and give the process a little time to react to it's absence, so any housekeeping necessary could be completed (exit gracefully) before the process is killed.
And MyDaemon:
#138 Wawrzek (http://wawrzek.name)
Nice code. butI have a problem and I'm not sure if it bug or maybe feature.
Let assume that we are calling our daemon as a normal user, but pidfile passed to your module is '/var/log/mydaemon.pid' (something where user cannot write). It seems that daemon dying quietly without any error message. Am I right?
#139 Kasun
Thank you very much for the code. I have been using, modifying this for some time for my needs and I thought of open sourcing it. Basically using my code you can call Daemon.daemonize() and then the rest of the code would run in daemon mode.
You can have a look at it in https://github.com/kasun/YapDi
#140 Sander Marechal (http://www.jejik.com)
#141 Sander Marechal (http://www.jejik.com)
#142 jazzuell
#143 aprendice
I want to convert my script in python a daemon but I am new in this and I dont know modifies the code that you placed here. Can you help me to do what i want?
thanks
#144 Sander Marechal (http://www.jejik.com)
#145 Anonymous Coward (http://deneme.com)
i want my deamon autostart when the ubuntu is started.
#146 Sander Marechal (http://www.jejik.com)
#147 sun
I am using your code to run my script as a daemon.
In the run() method,
I have an infinite loop which calls iterate() method after every few seconds.
I use time.sleep() between the calls to the iterate() method.
In the iterate() method,
I am creating other processes using subprocess.popen() command.
But when these processes complete, they turn zombies.
How do I prevent zombies in this case?
#148 Anonymous Coward
Also what's the best way to make this actively stay alive in your opinion? Some people suggest something in /etc/inittab, others suggest a cron job.
Thanks :)
#149 Sander Marechal (http://www.jejik.com)
Keeping it alive should probably not be part of the application. Leave that up to your users. Some will like Nagios, others Monit or Keepalived or some custom monitoring scripts.
#150 paroariax
Also what's the best way to make this actively stay alive in your opinion? Some people suggest something in /etc/inittab, others suggest a cron job.
Thanks :)
#151 paroariax
@Sander: So effectively I should have a shell script that simply passes the command line argument though to my python script? Seems like a bit of a waste, especially as I intend the entire application to be a single .py file so it's really simple for the client to use.
By the way, did you ever get a chance to combine all the contributed changes here into a Daemon v2.0? If not I'll do it and post it back here.
#152 Sander Marechal (http://www.jejik.com)
Think about what the init.d script is for. It's not for users. It for the computer. The init.d scripts exist for the system to automatically start and stop services when you switch runlevels. The only commandline arguments your system knows are "start" and "stop".
The init.d script exists to turn a complex custom command like:
into a simple command like this, which your computer understands:
So, you have /usr/bin/my-daemon.py which your users can use with all the complexity that your daemon provides. And you have /etc/init.d/my-dameon which only accepts "start" and "stop". And all the other commandline arguments you need you put into that init.d script. Your users can edit that init.d script to add/remove the commandline arguments they need.
As for v2.0, I haven't gotten around to it yet. I'm quite busy :-) There are two people who have taken this code and added some of the improvements. Both can be found at github:
https://github.com/kasun/YapDi
https://github.com/barberj/Saerpent
Perhaps you could collaborate with those two to get a canonical version with all the improvements in it and publish it on github? I'd be happy to directly link that from the article.
#153 Amir
Amir.
#154 geeky583
#155 Niklas (https://github.com/nthorne/xmppmote)
/Niklas
#156 David Karlsson (http://automagically.weebly.com)
#157 megrez80
I just wanted to give folks a heads up on a minor tweak I had to make in my situation. For some reason, the 2nd parent was failing to exit, which subsequently would prevent the killing of the child later on. I use os._exit to exit the 2nd parent instead of sys.exit.
#158 Anonymous Coward
- The start up race where two daemons can begin running simultaneously
- The failure to check the process table when establishing whether a process is running. If you have a data center outage or your daemon is sent sigkill, the last thing you want to worry about is a daemon failing to starting at boot.
- The ability for a third party to read the pid file with guaranteed coherent results.
These are remedied primarily by establishing an exclusive lock on the pidfile. Updated code below. Common code mostly omitted.
#159 Anonymous Coward
How do you pick a PID number?
How does one verify their daemon is running. I've checked my ps aux and I don't see my daemon running.
In my pid file I placed a random number 666 and ran the daemon, but I don't see anything in ps aux output...
I also made sure pid 666 is not in use prior to running the daemon.
Thanks,
AC
#160 Ariel Monaco
#161 Sander Marechal (http://www.jejik.com)
#162 jPLOS
Where you say:
" if err.find("No such process") > 0:"
Couldn't you get an off-by-one error if that string is actually at the beginning of the string? You could cover all your bases instead like so:
" if err.find("No such process") > 1:"
#163 Oleg
*/5 * * * * os pgrep -f /home/os/takeSpeed_8.py &>/dev/null || python /home/os/takeSpeed_8.py
#164 bbwolf
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
Any suggestions?
Thanks!
BB
#165 jiamo
daemon = MyDaemon('/tmp/daemon-example.pid',stdout=sys.stdout)
I may want to see daemon 's output when i am testing .
File "daemon-example.py", line 24, in <module>
daemon.start()
File "/home/engine/Zealot/src/release/xcc_server/daemon.py", line 84, in start
self.daemonize()
File "/home/engine/Zealot/src/release/xcc_server/daemon.py", line 52, in daemonize
so = file(self.stdout, 'a+')
TypeError: coercing to Unicode: need string or buffer, file found
#166 Sander Marechal (http://www.jejik.com)
#167 hagak
Comments have been retired for this article.