Como @ Marcos aclaró que es un sistema Linux, el guión podría fácilmente hacerse totalmente independiente, es decir, un demonio , siguiendo este recipe. (También puede hacerlo en el padre después de os.fork
y solo entonces os.exec...
el proceso secundario).
Editar: para aclarar algunos detalles Comentario de wrt @ mark sobre mi respuesta: los privilegios de superusuario no son necesarios para "daemonizar" un proceso según las recetas del libro de cocina, ni hay necesidad de cambiar el directorio de trabajo actual (aunque el código en la receta hace eso y más, esa no es la parte crucial, sino que es la secuencia lógica adecuada de las llamadas fork
, _exit
y setsid
). Las diversas variantes os.exec...
que hacen no terminan en e
utilizan el entorno del proceso principal, por lo que esa parte también es fácil - consulte Python online docs.
Para abordar sugerencias hechas en los comentarios y respuestas de otros: creo que subprocess
y multiprocessing
per se no daemonize el proceso secundario, que parece ser lo que @mark necesita; la secuencia de comandos podría hacerlo por sí mismo, pero desde un código tiene que estar haciendo fork
sy setsid
, me parece mejor mantener todo el desove en ese plano de bajo nivel en lugar de mezclar algunos de alto nivel y algunos bajos código de nivel en el curso de la operación.
Aquí hay una versión muy reducida y simplificada de la receta en la URL anterior, diseñada para ser llamada en el padre para generar un hijo daemon - de esta manera, el código se puede usar para ejecutar ejecutables que no sean de Python. . Como se indica, el código debe cumplir con las necesidades @mark explicadas, por supuesto, se puede adaptar de muchas maneras: recomiendo leer la receta original y sus comentarios y discusiones, así como los libros que recomienda, para obtener más información.
import os
import sys
def spawnDaemon(path_to_executable, *args)
"""Spawn a completely detached subprocess (i.e., a daemon).
E.g. for mark:
spawnDaemon("../bin/producenotify.py", "producenotify.py", "xx")
"""
# fork the first time (to make a non-session-leader child process)
try:
pid = os.fork()
except OSError, e:
raise RuntimeError("1st fork failed: %s [%d]" % (e.strerror, e.errno))
if pid != 0:
# parent (calling) process is all done
return
# detach from controlling terminal (to make child a session-leader)
os.setsid()
try:
pid = os.fork()
except OSError, e:
raise RuntimeError("2nd fork failed: %s [%d]" % (e.strerror, e.errno))
raise Exception, "%s [%d]" % (e.strerror, e.errno)
if pid != 0:
# child process is all done
os._exit(0)
# grandchild process now non-session-leader, detached from parent
# grandchild process must now close all open files
try:
maxfd = os.sysconf("SC_OPEN_MAX")
except (AttributeError, ValueError):
maxfd = 1024
for fd in range(maxfd):
try:
os.close(fd)
except OSError: # ERROR, fd wasn't open to begin with (ignored)
pass
# redirect stdin, stdout and stderr to /dev/null
os.open(os.devnull, os.O_RDWR) # standard input (0)
os.dup2(0, 1)
os.dup2(0, 2)
# and finally let's execute the executable for the daemon!
try:
os.execv(path_to_executable, args)
except Exception, e:
# oops, we're cut off from the world, let's just give up
os._exit(255)
¿Por qué no utiliza el subproceso.Pobre para hacer esto? –
S. Lott: ¿podré matar/reiniciar la aplicación web/proceso principal después de hacer el subproceso.Popen? gracias – mark