IO.popen y procesos zombies

Hola, trato de que mi aplicación Rails ejecute un comando de sistema en
background, recuperando el pid del proceso creado. Además dicho proceso
externo dura mucho tiempo y no debe bloquear a la aplicación web.

He probado con todo lo que he visto: “system”, “exec”, %x[ ] y IO.popen.

Sin duda la que mejor pinta tiene es IO.popen, ya que devuelve un objeto
de
tipo “proceso” con métodos para obtener el pid, la salida del comando,
permite mandar datos al comando…

El caso es que al ejecutarlo me crea procesos zombies que sólo mueren
cuando
mato manualmente al irb o a webrick (depende de dónde ejecute el
programa).

Por poner un ejemplo, mi código Rails ejecuta en un momento dado:

proc = IO.popen(“sleep 30”)

  • La aplicación Rails no espera 30 segundos sino que continúa la
    ejecución web
    (esto es bueno y requisito mío, pues el comando puede durar horas aunque
    en
    este ejemplo sean sólo 30 segundos).

  • Obtengo el pid sin más que “proc.pid”.

El problema es que cuando pasan esos 30 segundos el proceso “sleep”
queda
zombie:
ibc 26345 26255 0 02:35 pts/1 00:00:00 [sleep]

Hay dos formas de acabar con él:

  1. Matando webrick o el servidor web que sea (no me sirve, claro).

  2. Leyendo la salida del proceso o cerrándolo, de tal forma que el padre
    “irb
    o webrick” hace el “wait” y el hijo muere:
    proc.readlines
    ó
    proc.close
    Esto último en realidad no me sirve pues ambos métodos se quedan
    esperando a
    que el proceso acabe, lo que significa que se bloquea la aplicación
    Rails
    ¡¡durante una hora o más!!.

En fin, que después de muchas pruebas y de leerme todo el API de IO no
encuentro forma de lanzar un comando en background que dura mucho tiempo
y
poder olvidarme de él (simplemente por el problema de que queda como
zombie
ocupando recursos).

¿A alguien se le ocurre algo? Muchas gracias por cualquier sugerencia.

PD: Si lanzo el comando con:
system “sleep 30 &”
desaparece completamente el problema del proceso zombie, es más, el
comando “sleep” sigue corriendo incluso aunque mate a webrick, lo cuál
es
perfecto para mi aplicación.
El único problema es que con “system” no tengo ni idea de cómo recuperar
el
pid del proceso creado (y me hace falta). Tal vez sea más fácil
solventar el
asunto por este lado, pero necesito averiguar el pid.

Gracias de nuevo.

On 11/29/06, Iñaki [email protected] wrote:

comando “sleep” sigue corriendo incluso aunque mate a webrick, lo cuál es
perfecto para mi aplicación.

Claramente lo que necesitas es hacer un wait del pid en cuestión.
Esto en C lo he hecho alguna que otra vez, pero no en Ruby. Le he
echadoun vistazo a IO y Kernel, y por lo que entiendo deberías poder
capturar, con Kenerl::trap la señal SIGCHLD que te enviará el sistema
operativo cuando uno de los hijos que hayas lanzado termine.
Entonces, y sólo entonces, haces un Process::wait, de forma que el hio
no queda zombie y tú no has detenido la ejecución de tu programa -sólo
haces el wait cuando el SO te indica que ha terminado el hijo-.

El único problema es que con “system” no tengo ni idea de cómo recuperar el
pid del proceso creado (y me hace falta). Tal vez sea más fácil solventar el
asunto por este lado, pero necesito averiguar el pid.

Alternativamente, puedes crear un fichero donde escribas el pid del
proceso y ejecutarlo cno el system.

en la conferencia rails hubo una charla precisamente sobre los procesos
en background y se hizo una demostración con la librería backgroundrb
cuando suban las transparencias de las charlas(o busca algún howto),
échale un vistazo porque parecía bastante sencillo de implementar
http://backgroundrb.rubyforge.org/

saludos

On Wed, 2006-11-29 at 03:00 +0100, Iñaki wrote:

El caso es que al ejecutarlo me crea procesos zombies que sólo mueren cuando

  • Obtengo el pid sin más que “proc.pid”.
    o webrick" hace el “wait” y el hijo muere:
    poder olvidarme de él (simplemente por el problema de que queda como zombie
    El único problema es que con “system” no tengo ni idea de cómo recuperar el
    pid del proceso creado (y me hace falta). Tal vez sea más fácil solventar el
    asunto por este lado, pero necesito averiguar el pid.

Gracias de nuevo.


/**

El Miércoles, 29 de Noviembre de 2006 15:02, Hernan F. escribió:

Te recomiendo mirar el manual de ruby, te lo comento de memoria, y no es
algo que hago seguido esto :wink:

Saludos

Muchas gracias a los 3 por las interesantes sugerencias. Veo que hay más
alternativas de las que había encontrado.

Gracias de nuevo :wink:

Iñaki,
Popen no te sirve para lo que quieres hacer, popen lo que hace es correr
el
comando como un subproceso y le conecta el estandar Input/output para
que
puedas comunicarte con él.
En el caso de una app web, me parece que te va a quedar el request
colgado
hasta que termine el hijo que “paristes” :wink:
Lo que necesitas hacer es algo parecido a esto:

pid = Process.fork { ‘sleep 30’}

Te recomiendo mirar el manual de ruby, te lo comento de memoria, y no es
algo que hago seguido esto :wink:

Saludos

El Miércoles, 29 de Noviembre de 2006 11:04, Borja Martín escribió:

en la conferencia rails hubo una charla precisamente sobre los procesos
en background y se hizo una demostración con la librería backgroundrb
cuando suban las transparencias de las charlas(o busca algún howto),
échale un vistazo porque parecía bastante sencillo de implementar
http://backgroundrb.rubyforge.org/

Efectivamente he encontrado las transparencias y es realmente
interesante:
http://bee.com.es/pdfs/confrails-backgrounDRb.pdf

Gracias.