2012-03-12 6 views
10

In Ruby 1.9.x, quale potrebbe essere un modo semplice per non consentire lo script di Ruby di essere eseguito di nuovo, o attendere il completamento dell'istanza precedente? **Come limitare le istanze concorrenti dello stesso script Ruby?

Spero di evitare il blocco file disordinato o controllo della tabella di processo.

C'è qualcosa come un global mutex o semaforo già nel nucleo? Ho studiato il codice nativo Mutex ma sembra che si applichi solo ai thread all'interno di un processo Ruby, non tra diversi processi.

** In seguito potrei aggiungere funzionalità di timeout o limite a istanze N o cercare di utilizzare più di un blocco globale (uno per risorsa a livello di sistema che dovrebbe avere solo un'istanza massima).

risposta

2

Questo è in genere risolto a livello di sistema operativo, controllando la presenza di un file di flag e non tentando di riavviarlo, non nello script stesso.

Tuttavia, se si desidera verificare lo script, cercare un file semaforo in una posizione nota. Se esiste e non è all'interno di una finestra temporale specifica che si adatta alla finestra di avvio, quindi eliminare il file e crearne uno nuovo. Se è nella tua finestra temporale, esci.

È possibile utilizzare il blocco dei file o la memorizzazione di timestamp nel file o molti altri controlli se non si avvia utilizzando un meccanismo di tipo cron. Ogni approccio ha i suoi vantaggi e svantaggi.

Si desidera intercettare gli interrupt in modo che quando si esce da un Control-C si cancella anche quel file.

Leggere le domande correlate a destra. Anche se coprono varie altre lingue, le risposte suggerite aiuteranno a capire i problemi e i possibili modi per aggirarli in tutte le lingue.

+0

Ho già inserito la maggior parte dei miei Ruby con script Bash che usano loro stessi codice come '[-z" $ (pidof -x -o% PPID -o $$ $ {0 ## * /}) "] || exec echo "$ (data) $ 0: $$ odora già PID: $ (pidof -x $ 0), ... ciao !!" 'comunque questo serve ad altri scopi. Una soluzione ancora migliore già contenuta all'interno di Ruby è quella di bloccare qualsiasi file fisso per la scrittura, ad es. '/ Tmp/scriptname.rb.lock'. All'uscita o anche se il mio codice si arresta in modo anomalo (cosa che spesso genera eccezioni) il sistema cancellerà quel blocco. Vado con quel trucco fino a quando non ci sarà un'interfaccia nativa pulita ai semafori globali - di cui avrò comunque bisogno. – Marcos

5

Questo brevissimo codice si blocca sul posto fino a un file di lock in/tmp chiamato dopo lo script è bloccato esclusivamente:

File.open("/tmp/#{File.basename $0}.lock", File::RDWR|File::CREAT, 0644).flock(File::LOCK_EX) 

Qualsiasi altro programma bloccandolo, Ruby o no, ha solo bisogno di chiudere o essere uccisi , per l'istanza di processo più recente da sbloccare e continuare. Quindi per ora questa soluzione fa quello che mi serve. Posso chiamare il mio programma rubino con

timeout 1m ./myrubyscript.rb 

dal confezionamento bash script se mi si rizzano i capelli, per esempio. (Nell'esempio, myrubyscript.rb termina dopo 1 minuto o meno e ha ottenuto il blocco del file per continuare a fare ciò che è stato scritto.)