views:

200

answers:

5

I have a working Python based program that I want to run as a daemon. Currently I'm doing it in a very hackish manner of starting it in with screen-d -m name session and killing it with pkill -9 -f name.

Eventually I'm doing to have to move this to the better system we use here (thus I'm not willing to modify the program) but in the interim, I'm looking for a cleaner way to do this.

My current thinking is kick it off as a background task from an inti.d script but how do I write the part to bring it back down?

+3  A: 

See PEP 3143 -- Standard daemon process library

vartec
+1  A: 

Starting it with an init.d style script is a good way. You take it down with POSIX Signals ... See StackOverflow, Signal handling in Python.

Aiden Bell
I can `kill -9` it for all I care, but I don't know how to reliably find its PID.
BCS
@BCS: `-9` is often ... *overkill* (pardon the pun). See [kill -9](http://speculation.org/garrick/kill-9.html). As for finding its PID, your script can create a pidfile in `/var/run` or use a lib that allows you to set `argv[0]` to some easily identified name for use with `pkill`.
Dennis Williamson
+5  A: 

On linux there is a start-stop-daemon utility as part of the init.d tools.

It is very flexible and allows different ways for capturing the pid of your server.

There is also a file /etc/init.d/skeleton which can serve as a basis for your own init.d script.

If your target platform is debian based, it makes sense to create a debina package to deploy it as it also helps getting a daemon properly integrated in the rest of the system. And it is not too complicated (if you have done it ten times before ;-)

Peter Tillemans
Looks like good stuff.
BCS
+2  A: 

If you want to do it with code in python, this is a pretty standard C-method that was ported to python that I use. It works flawlessly, and you can even choose a file output.

import os
import signal
def daemonize(workingdir='.', umask=0,outfile='/dev/null'):
#Put in background
pid = os.fork()
if pid == 0:
    #First child
    os.setsid()
    pid = os.fork() #fork again
    if pid == 0:
        os.chdir(workingdir)
        os.umask(umask)
    else:
        os._exit(0)
else:
    os._exit(0)

#Close all open resources
try:
    os.close(0)
    os.close(1)
    os.close(2)
except:
    raise Exception("Unable to close standard output. Try running with 'nodaemon'")
    os._exit(1)

#Redirect output
os.open(outfile, os.O_RDWR | os.O_CREAT)
os.dup2(0,1)
os.dup2(0,2)

Then, you can use signals to catch when a kill-signal was sent to the program and exit nicely. Example from Python Docs

import signal, os

def handler(signum, frame):
    print 'Signal handler called with signal', signum
    raise IOError("Couldn't open device!")

# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)

# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)

signal.alarm(0)          # Disable the alarm
Chris
the double fork method works like a charm!
pygabriel
A: 

Try this question or more exactly accepted solution.

Ib33X
I'd really rather not muck with the internals of the program. Heck I'd rather keep what I'm using now rather than do that.
BCS
Really you don't need to change your program, if it is importable. Joust import your main in deamon-example Run method, (replace while loop).
Ib33X