2009-02-13 4 views
3

Dans mon application Rails, j'ai un script qui met à jour certains enregistrements dans la base de données. Quand j'envoie un SIGTERM pour tuer le script, il reçoit parfois ce signal pendant que ActiveRecord exécute une requête. Cela conduit à une exception ActiveRecord :: StatementInvalid levée.ActiveRecord :: StatementInvalid lorsque le processus reçoit SIGTERM?

J'aimerais attraper des exceptions StatementInvalid qui se produisent lorsqu'elles sont le résultat d'un SIGTERM et quittent le script. Comment puis-je savoir qu'un StatementInvalid se produit à cause d'un signal et non pour une autre raison?

+0

Y at-il quelque chose d'autre que vous cherchez pour fermer cette question? – wuputah

Répondre

0

Il semble que ce "script" soit externe à l'application Rails (script/runner ou similaire?), Alors peut-être que vous pouvez découpler le "gestionnaire de signal" et "travailleur"? Par exemple, pouvez-vous forker un enfant processus/thread/fibre/... pour faire la mise à jour de la base de données, et signaler au parent d'indiquer "stop now"? Bien sûr, le parent devra alors "signaler" à l'enfant d'arrêter d'utiliser un mécanisme approprié (pas SIGTERM ;-)).

5

Si vous piègez le signal TERM, je crois que vous éviterez l'exception. Vous pouvez le faire au début de votre script (ou vraiment n'importe où d'ailleurs, mais vous n'avez besoin de le faire qu'une seule fois).

Signal.trap("TERM") do 
    Kernel.exit! 
end 

La raison pour laquelle vous obtenez l'erreur StatementInvalid Ruby gère le signal en soulevant une exception SIGTERM au lieu de l'exécution en cours. ActiveRecord intercepte l'exception et la réenregistre en tant que StatementInvalid. En définissant un gestionnaire de signal, Ruby exécutera votre gestionnaire au lieu de déclencher une exception. Pour plus d'informations, reportez-vous au Ruby Signal documentation.

+0

Fixe, doit utiliser Kernel.exit! pour que cela fonctionne. Preuve par l'exemple: http://gist.github.com/66735 – wuputah

+0

En supposant que ce type de sortie est "normal", vous voulez probablement 'Kernel.exit! vrai'. Taht façon le processus sortira avec un statut de 0. – johnf

0

Ceci n'est pas une réponse exacte à l'OP, cependant, vous pouvez contrôler le point de sortie - le programme ne sortira qu'après avoir atteint le point de sortie que vous avez défini.

time_to_die=false 

# Prevent abrupt stopping of the daemon. 
Signal.trap("TERM") { time_to_die=true; "SIG_IGN" } 

loop { 
    . 
    . 
    exit_gracefully if time_to_die 
    . 
    . 
} 

def exit_gracefully 
    #Cleaning up.. 
    $log.log "#{Time.now} TERM signal received. Exiting.." 
    $db.close 
    exit 
end 
Questions connexes