2011-12-07 11 views
6

Mam podobny problem do this other post i próbowałem podanych rozwiązań, ale na próżno.Jak wychwytujesz wyjątki w implementacji EventMachine?

Mój projekt to bot Ruby, który używa biblioteki Blather do łączenia się z serwerem Jabber. Problem polega na tym, że gdy występuje problem z serwerem i Blather generuje wyjątek, cały program kończy działanie i nie mam możliwości złapania wyjątku.

Oto prosty kod, który pokazuje problem. Nie ma serwera Jabber uruchomionego na localhost, więc klient Blather zgłasza wyjątek. Miałem wrażenie, że EM.error_handler {} będzie w stanie go przechwycić, ale nigdy nie widzę komunikatu **** ERROR i program się zatrzymuje. :(

#!/usr/bin/env ruby 
require 'rubygems' 
require 'blather/client/client' 

EM.run do 
    EM.error_handler { puts " **** ERROR " } 

    Blather::Stream::Client.start(
    Class.new { 
    }.new, '[email protected]', 'echo') 
end 

Myślę, że problemem jest to, że blather wykorzystuje również EventMachine a może dzwoni EM.stop, który powoduje, że zewnętrzna instancja EM przestać.

Odpowiedz

5

Wyjątki i programowanie asynchroniczne nie są przyjaciółmi, więc może być trudny do prawidłowego obsługiwania.W modelu synchronicznym wyjątek może zostać przechwycony przez użycie rescue na bloku kodu, który może generować wyjątki, ale po utworzeniu metody wywołania zwrotnego ten blok potrzebuje własnej obsługi wyjątków, ponieważ będzie działać na zewnątrz

Mam nadzieję, że error_handler pochwyci twój wyjątek, ale jeśli masz inne wątki, które mogą nie być w stanie ich uchwycić.

Zawsze można monkeypatch EventMachine.stop_event_loop i EventMachine.stop_server sprawdzić, czy jest to metoda, która jest wywoływana.

+0

Hmmm ... to mniej niż optymalne rozwiązanie. 'error_handler' * powinno * łapać te rzeczy, ale nie z jakiegoś powodu. Podam opcję poprawki małpy i zobaczę, czy mogę "rozwiązać" mój problem w ten sposób. :/ –

+0

Poprawka małpy służy tylko do sprawdzenia, czy te metody są wywoływane, ponieważ po tym czasie nie są już wymagane. – tadman

2

Mechanizm obsługi błędu przechwytuje wyjątki, które występują podczas wykonywania wywołań zwrotnych wyzwalanych w pętli zdarzeń. Nie uruchomisz pętli w momencie awarii powyższego kodu. (Zakładam, że to Blather :: Stream.start zamiast Blather :: Stream :: Client.start powyżej).

Możesz spróbować zrobić EM.next_tick {Blather :: Stream.start (...)}, który zmusi go do wykonania podczas pętli reaktora.

Ale na ogół nie chcesz kontynuować po uruchomieniu obsługi błędu error_handler. Jest to w zasadzie linia ostatniej obrony, aby oczyścić dowolny stan i wyjść (i wydrukować ślad stosu, aby wiedzieć, dlaczego aplikacja się zawiesiła). Kiedy się odpala, nie masz pojęcia, jaki jest obecny stan twojej aplikacji i naprawdę nie możesz ufać, że państwo jest poprawne lub spójne.

Teoretycznie, można po prostu zawinąć blather połączenia w Rozpocznij/ratunek:

begin 
    Blather::Stream.start(...) 
rescue Exception => e 
    puts e 
end 

Które powinno wystarczyć dla Ciebie, można to trzymać w pewnej logiki ponawiania.