Estoy intentando crear un demonio Python que inicie otros procesos totalmente independientes.Desove indefinido de procesos daemonizados en Python
La idea general es para un comando de shell dado, realice sondeos cada pocos segundos y asegúrese de que se ejecutan exactamente k instancias del comando. Guardamos un directorio de archivos pidfiles, y cuando sondeamos eliminamos los archivos pid cuyos pids ya no se ejecutan y se inician (y hacen los archivos pidf) para todos los procesos que necesitamos para obtener k de ellos.
Los procesos secundarios también deben ser totalmente independientes, de modo que si el proceso principal fallece, los hijos no serán eliminados. Por lo que he leído, parece que no hay forma de hacerlo con el módulo subprocess
. Con este fin, he usado el fragmento mencionado aquí:
http://code.activestate.com/recipes/66012-fork-a-daemon-process-on-unix/
Hice un par modificaciones necesarias (verá las líneas comentadas en el fragmento adjunta):
- El principal original proceso no puede salir porque necesitamos que el daemon iniciador perdure indefinidamente.
- Los procesos secundarios deben comenzar con el mismo elemento secundario que el primario.
Aquí es mi engendro fn y una prueba:
import os
import sys
import subprocess
import time
def spawn(cmd, child_cwd):
"""
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) # parent daemon needs to stay alive to launch more in the future
return
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("/") # we want the children processes to
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('/dev/null', 'r')
so = file('/dev/null', 'a+')
se = file('/dev/null', 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
pid = subprocess.Popen(cmd, cwd=child_cwd, shell=True).pid
# write pidfile
with open('pids/%s.pid' % pid, 'w') as f: f.write(str(pid))
sys.exit(1)
def mkdir_if_none(path):
if not os.access(path, os.R_OK):
os.mkdir(path)
if __name__ == '__main__':
try:
cmd = sys.argv[1]
num = int(sys.argv[2])
except:
print 'Usage: %s <cmd> <num procs>' % __file__
sys.exit(1)
mkdir_if_none('pids')
mkdir_if_none('test_cwd')
for i in xrange(num):
print 'spawning %d...'%i
spawn(cmd, 'test_cwd')
time.sleep(0.01) # give the system some breathing room
En esta situación, las cosas parecen funcionar bien, y los procesos secundarios persisten incluso cuando el padre se mató. Sin embargo, todavía estoy corriendo en un límite de generación en el padre original. Después de ~ 650 desova (no al mismo tiempo, los niños han terminado) el proceso padre se ahoga con el error:
spawning 650...
fork #2 failed: 35 (Resource temporarily unavailable)
¿Hay alguna manera de volver a escribir mi función de desove para que pueda generar estos procesos secundarios independientes indefinidamente? ¡Gracias!
¿Cómo es la tabla de proceso? ¿'Ps aux' muestra una gigantesca pila de procesos zombies esperando ser cosechados? (No veo ningún código aquí para 'wait()' en los primeros bifurcados). – sarnold
Creo que sí: http://pastebin.com/qDrFmHWk –
Considere pyinotify para supervisar los cambios en un directorio en su lugar de votación. – aitchnyu