2011-12-31 15 views
25

Ho recentemente iniziato a sperimentare l'uso di Python per lo sviluppo web. Finora ho avuto qualche successo usando Apache con mod_wsgi e il framework web Django per Python 2.7. Tuttavia mi sono imbattuto in alcuni problemi con i processi costantemente in esecuzione, l'aggiornamento delle informazioni e così via.Come posso eseguire processi Python a lungo termine (infinito)?

Ho scritto uno script che chiamo "daemonManager.py" che può avviare e arrestare tutti o singoli loop di aggiornamento di Python (Devo chiamarli Daemon?). Lo fa biforcandosi, quindi caricando il modulo per le funzioni specifiche che dovrebbe eseguire e avviare un ciclo infinito. Salva un file PID in /var/run per tenere traccia del processo. Fin qui tutto bene. I problemi che ho riscontrato sono:

  • Ogni tanto uno si arresta. Controllo lo ps di mattina e il processo è appena finito. Non sono stati registrati errori (sto utilizzando il modulo logging) e sto trattando tutte le eccezioni che riesco a pensare e registrarle. Inoltre, non penso che questi processi di chiusura abbiano qualcosa a che fare con il mio codice, perché tutti i miei processi eseguono codice completamente diverso e escono a intervalli abbastanza simili. Naturalmente potrei sbagliarmi. È normale che i processi Python muoiano solo dopo che sono stati eseguiti per giorni/settimane? Come dovrei affrontare questo problema? Devo scrivere un altro demone che controlli periodicamente se gli altri demoni sono ancora in esecuzione? Cosa succede se quel demone si ferma? Sono in perdita su come gestirlo.

  • Come posso sapere a livello di programmazione se un processo è ancora in esecuzione o no? Sto salvando i file PID in /var/run e controllando se il file PID è lì per determinare se il processo è in esecuzione o meno. Ma se il processo muore solo per cause impreviste, il file PID rimarrà. Devo quindi eliminare questi file ogni volta che un processo si blocca (un paio di volte alla settimana), che tipo di sconfigge lo scopo. Immagino che potrei controllare se un processo è in esecuzione al PID nel file, ma cosa succede se un altro processo è iniziato e gli è stato assegnato il PID del processo morto? Il mio demone penserebbe che il processo stia funzionando bene anche se è morto da tempo. Ancora una volta non riesco a capire come affrontarlo.

una soluzione utile su come migliori eseguire processi infinita di Python, si spera anche spargimento po 'di luce sui problemi di cui sopra, accetterò


Sto usando Apache 2.2.14 su una macchina Ubuntu.
La mia versione di Python è 2.7.2

+0

Se si aggiungono alcuni esempi di codice che mostrano il codice per i daemon in crash, potremmo essere in grado di rispondere a specifiche. Per prima cosa, rimuoverei tutto il codice dagli script che trattano il biforcarsi, il monitoraggio, il reindirizzamento, ecc. –

+0

Puoi chiarire se stai forking questi processi daemon dall'applicazione WSGI in esecuzione in mod_wsgi o separatamente. Non si dovrebbe fare la creazione di questo processo da un'applicazione in esecuzione in mod_wsgi. –

+0

Sembra che ci sia molta pubblicità qui. Voglio dire, questa è una domanda ben piazzata, sulla quale viene data una risposta a una tecnologia specifica, a cui viene data un'altra risposta in cui viene replicata di nuovo "Ho anche finito per usare" un'altra tecnologia (competitiva?) ... – citn

risposta

24

Si aprirà affermando che questo è un modo per gestire un processo a esecuzione prolungata (LRP) - non di fatto con qualsiasi allungamento.

Nella mia esperienza, il miglior prodotto possibile deriva dal concentrarsi sul problema specifico con cui si ha a che fare, delegando la tecnologia di supporto ad altre librerie. In questo caso, mi riferisco all'atto dei processi di backgrounding (l'arte della doppia forcella), al monitoraggio e al reindirizzamento dei log.

La mia soluzione preferita è http://supervisord.org/

Utilizzando un sistema come supervisord, che, fondamentalmente, scrive uno script python convenzionale che esegue un compito mentre bloccato in un ciclo "infinito".

#!/usr/bin/python 

import sys 
import time 

def main_loop(): 
    while 1: 
     # do your stuff... 
     time.sleep(0.1) 

if __name__ == '__main__': 
    try: 
     main_loop() 
    except KeyboardInterrupt: 
     print >> sys.stderr, '\nExiting by user request.\n' 
     sys.exit(0) 

Scrivere lo script in questo modo rende più semplice e conveniente per sviluppare ed eseguire il debug (si può facilmente avviare/fermare in un terminale, a guardare l'output del registro come lo svolgersi degli eventi). Quando arriva il momento di avviare la produzione, devi semplicemente definire una configurazione supervisore che chiami il tuo script (ecco l'esempio completo per la definizione di un "programma", in gran parte opzionale: http://supervisord.org/configuration.html#program-x-section-example).

Supervisor ha un mucchio di opzioni di configurazione in modo da non li elencherò, ma devo dire che risolve specificamente i problemi che si descrivono:

  • backgrounding/Daemonizing
  • PID tracking (can essere configurato per riavviare un processo in caso di interruzione imprevista)
  • Accedere normalmente allo script (gestore flusso se si utilizza il modulo di registrazione anziché stampare), ma consentire al supervisore di reindirizzare a un file.
+0

Ho finito per scaricare la mia soluzione demonizzata in quanto risulta che non ho abbastanza esperienza sull'argomento. Ho anche finito di usare [forever by nodejitsu] (https://github.com/nodejitsu/forever) che è una deliziosa applicazione no-config-richiesta (ma tonnellate di config possibile) in cui devi solo specificare l'eseguibile e gli argomenti, e lo script verrà eseguito come un demone per sempre, riavviando quando si blocca. Ho anche risolto alcuni bug di lunga durata controllando i log di output automatici. Accetto la tua risposta come quella più vicina alla mia soluzione – Hubro

+0

Will Supervisor riavvierà lo script dopo aver chiuso manualmente lo script? –

+1

@Jakobud quando il supervisore sta gestendo un processo che esce (tramite 'sys.exit()', un'eccezione non rilevata, o se lo script raggiunge la sua fine, forse non c'è un ciclo?), Tenterà di riavviarlo. Esistono impostazioni per controllare il numero di tentativi di riavvio da effettuare e il tempo di attesa tra un tentativo e l'altro. Una volta che tutti i tentativi sono stati spesi, si arrenderanno. Se si desidera interrompere un lavoro in esecuzione, è necessario utilizzare supervisorctl per arrestarlo. Il supervisore –

2

Suppongo che tu stia utilizzando Unix/Linux ma non dici veramente. Non ho consigli diretti sul tuo problema. Quindi non mi aspetto di essere la risposta "giusta" a questa domanda. Ma c'è qualcosa da esplorare qui.

Innanzitutto, se i tuoi daemon si bloccano, devi risolvere il problema. Solo i programmi con bug dovrebbero bloccarsi. Forse dovresti avviarli sotto un debugger e vedere cosa succede quando si bloccano (se possibile). Avete qualche traccia di registrazione in questi processi? In caso contrario, aggiungili. Questo potrebbe aiutare a diagnosticare il tuo incidente.

In secondo luogo, i tuoi daemon forniscono servizi (apertura di pipe e in attesa di richieste) o stanno eseguendo una pulizia periodica? Se si tratta di processi di pulizia periodici, è necessario utilizzare cron per avviarli periodicamente anziché eseguirli in un ciclo infinito. I processi Cron dovrebbero essere preferiti rispetto ai processi demone. Allo stesso modo, se sono servizi che aprono porte e richieste di servizi, hai pensato di farli funzionare con INETD? Di nuovo, un singolo daemon (inetd) dovrebbe essere preferito a un gruppo di processi demone.

In terzo luogo, il salvataggio di un PID in un file non è molto efficace, come hai scoperto. Forse un IPC condiviso, come un semaforo, funzionerebbe meglio. Non ho alcun dettaglio qui però.

In quarto luogo, a volte ho bisogno di cose da eseguire nel contesto del sito web. Io uso un processo cron che chiama wget con un URL di manutenzione. Tu imposti un cookie speciale e includi le informazioni sui cookie con la riga di comando di wget. Se il cookie speciale non esiste, restituire 403 anziché eseguire il processo di manutenzione. L'altro vantaggio qui è il login al database e altri problemi ambientali da evitare poiché il codice che serve le normali pagine web sta servendo il processo di manutenzione.

La speranza che ti dà idee. Penso che evitare i demoni, se puoi, è il miglior punto di partenza. Se puoi eseguire il tuo python all'interno di mod_wsgi che ti risparmia devi supportare più "ambienti". Il debug di un processo che fallisce dopo l'esecuzione per giorni alla volta è semplicemente brutale.

+1

Grazie per il buon consiglio. Preciso che sto utilizzando Ubuntu a proposito :) – Hubro

+0

Oh, alla fine. Non l'ho visto – jmucchiello

2

Si dovrebbe considerare i processi Python come in grado di funzionare "per sempre" assumendo che non si abbiano perdite di memoria nel programma, nell'interprete Python o in qualsiasi libreria/modulo Python che si sta utilizzando. (Anche di fronte alle perdite di memoria, potresti essere in grado di girare all'infinito se hai uno spazio di swap sufficiente su una macchina a 64 bit. Decenni, se non secoli, dovrebbero essere fattibili. due anni su hardware limitato - prima che l'hardware necessitasse di essere spostato.)

programmi Garantire riavviare quando muoiono usato per essere molto semplice indietro quando le distribuzioni di Linux usati SysV-style init - basta aggiungere una nuova linea per la /etc/inittab e init(8) sarebbe generare il vostro programma in fase di avvio e di re-spawn se muore. (Non conosco nessun meccanismo per replicare questa funzionalità con il nuovo upstartinit -Sostituzione che molte distribuzioni stanno usando in questi giorni. Non sto dicendo che è impossibile, io non so come farlo.)

Ma anche il meccanismo init(8) degli anni passati non era flessibile come alcuni avrebbero voluto. Il pacchetto daemontools di DJB è un esempio di strumenti di controllo e monitoraggio dei processi per mantenere i demoni in vita per sempre. La suite Linux-HA fornisce un altro strumento simile, anche se potrebbe fornire troppo funzionalità "extra" per giustificare questa attività. monit è un'altra opzione.

Problemi correlati