2010-01-02 14 views
7

sto provando a configurare un server per i test di integrazione (in realtà le specifiche) tramite Ruby e non riesco a capire come controllare il processo.come controller (start/kill) un processo in background (app server) in ruby ​​

così, quello che sto cercando di fare è:

  1. eseguire un'attività rastrello per la mia gemma che esegue le specifiche di integrazione
  2. l'attività deve iniziare prima di un server (io uso webrick) e quindi eseguire le specifiche
  3. dopo l'esecuzione delle specifiche dovrebbe uccidere il webrick quindi non sono andato con alcuni inutilizzati processo in background

webrick non è un requisito, ma è inclusa nel libra standard di rubino quindi essere in grado di usarlo sarebbe fantastico.

sperare che qualcuno sia in grado di aiutare!

ps. sto lavorando su Linux, quindi avere questo lavoro per Windows non è la mia priorità principale (in questo momento).

risposta

12

Il modo standard è utilizzare il fork delle funzioni di sistema (per duplicare il processo corrente), exec (per sostituire il processo corrente con un file eseguibile) e kill (per inviare un segnale a un processo per terminarlo).

Ad esempio:

pid = fork do 
    # this code is run in the child process 
    # you can do anything here, like changing current directory or reopening STDOUT 
    exec "/path/to/executable" 
end 

# this code is run in the parent process 
# do your stuffs 

# kill it (other signals than TERM may be used, depending on the program you want 
# to kill. The signal KILL will always work but the process won't be allowed 
# to cleanup anything) 
Process.kill "TERM", pid 

# you have to wait for its termination, otherwise it will become a zombie process 
# (or you can use Process.detach) 
Process.wait pid 

Questo dovrebbe funzionare su qualsiasi Unix come sistema. Windows crea il processo in un modo diverso.

+0

ottimo. Grazie mille. mentre provavo le cose, avevo una "soluzione" quasi identica che funzionava quasi, ma non riesco a capire dove fosse diverso. inoltre avevo bisogno di aggiungere un sonno dopo aver forato il processo per aspettare che il server fosse disponibile. Grazie! – rubiii

+0

sono riuscito a riprodurre la differenza. Ho eseguito il sistema Kernel # invece di Kernel # exec. Kernel # exec "sostituisce il processo corrente eseguendo il comando esterno specificato" dove Kernel # system "esegue il comando in una subshell". – rubiii

+0

Il processo figlio può rimanere attivo anche se lo script rubino viene chiuso? –

0

Ho provato la forcella, ma ha problemi quando ActiveRecord è coinvolto in entrambi i processi. Vorrei suggerire il plugin Spawn (http://github.com/tra/spawn). Fa solo fork, ma si prende cura di ActiveRecord.

+0

se hai bisogno di ar, la soluzione potrebbe essere la strada da percorrere. quindi grazie. ma non ho davvero bisogno di usare AR. – rubiii

2

Ho appena dovuto fare qualcosa di simile e questo è quello che mi è venuto in mente. @Michael Witrant's risposta mi ha fatto iniziare, ma ho cambiato alcune cose come l'utilizzo di Process.spawn invece di fork (newer and better).

# start spawns a process and returns the pid of the process 
def start(exe) 
    puts "Starting #{exe}" 
    pid = spawn(exe) 
    # need to detach to avoid daemon processes: http://www.ruby-doc.org/core-2.1.3/Process.html#method-c-detach 
    Process.detach(pid) 
    return pid 
end 

# This will kill off all the programs we started 
def killall(pids) 
    pids.each do |pid| 
     puts "Killing #{pid}" 
     # kill it (other signals than TERM may be used, depending on the program you want 
     # to kill. The signal KILL will always work but the process won't be allowed 
     # to cleanup anything) 
     begin 
     Process.kill "TERM", pid 

     # you have to wait for its termination, otherwise it will become a zombie process 
     # (or you can use Process.detach) 
     Process.wait pid 
     rescue => ex 
     puts "ERROR: Couldn't kill #{pid}. #{ex.class}=#{ex.message}" 
     end 
    end 
end 

# Now we can start processes and keep the pids for killing them later 
pids = [] 
pids << start('./someprogram') 

# Do whatever you want here, run your tests, etc. 

# When you're done, be sure to kill of the processes you spawned 
killall(pids) 

Questo è tutto ciò che ha scritto, provatelo e fatemi sapere come funziona.

Problemi correlati