2012-01-26 22 views
7

Mam aplikacji uruchomionych na Heroku, że od czasu do czasu, donosi Timeout :: Error i (actionView :: Template :: Error) "wykonanie wygasł".Uchwyt TimeOut :: Błąd ponownego

Zdarza się to na całej stronie internetowej (tj. Nie w określonym kontrolerze), dlatego chciałbym utworzyć funkcję, która obsłuży te dwa błędy, najpierw poprzez dwukrotne ponowienie próby i przekierowanie użytkownika na stronę, która powie im że serwer jest zajęty.

Mój obecny plan jest użycie następujących ApplicationController:

rescue_from Timeout::Error, :with => :rescue_from_timeout 

    def rescue_from_timeout 
    sleep 2 
    retry 
    end 

ale to tylko pętli i pętla. Chcę, żeby się złamała po dwóch próbach. Jak mogę to zrobić?

Ponadto, Jak mogę obsługiwać ActionView :: Template :: Błąd "wykonania wygasł"? Nie chcę ratować całego ActionView :: Template :: Błąd z ponownymi próbami, tylko te, które powodują "wykonanie wygasło".

To właśnie mój wyjątek mówi:

[Exception] home#index (ActionView::Template::Error) "execution expired" 

lub

[Exception] calculations#result (ActionView::Template::Error) "Timeout::Error: execution expired 

Moje pytanie zatem: Jak mogę obsługiwać te dwa rodzaje błędów przez pierwszy ponownego dwukrotnie, a następnie rzucać wyjątek/przekierować do strony błędu?

+1

Dlaczego ten wyjątek został podniesiony? Czy wdrożyłeś jakieś długotrwałe zadania, czy twoja aplikacja zależy od zewnętrznej usługi internetowej? – Jef

Odpowiedz

15

Zdefiniuj tę metodę:

def retryable(options = {}) 
    opts = { :tries => 1, :on => Exception }.merge(options) 

    retry_exception, retries = opts[:on], opts[:tries] 

    begin 
    return yield 
    rescue retry_exception 
    if (retries -= 1) > 0 
     sleep 2 
     retry 
    else 
     raise 
    end 
    end 
end 

I zadzwonić z tym:

retryable(:tries => 10, :on => Timeout::Error) do 
    your_code_here 
end 

Można umieścić to w around_filter w kontrolerze aplikacji, która jest klasą bazową dla wszystkich regulatorów w Rails aplikacja:

class ApplicationController < ActionController::Base 

    around_filter :retry_on_timeout 

    def retry_on_timeout 
    retryable(:tries => 10, :on => Timeout::Error) do 
     yield 
    end 
    end 
end 
+1

Dzięki, Douglas. Nie jestem jednak pewien, gdzie/jak korzystać z kodu wywołującego. Jeśli chcę go użyć, aby złapał ten błąd na całej stronie, to zgaduję, że w kontrolerze aplikacji miałbym coś, co nazywa się before_filter lub coś podobnego. Czy muszę zawijać każdego kontrolera itp. Za pomocą funkcji ponownej próby? Czy mógłbyś wyjaśnić, w jaki sposób mogę użyć tego, aby złapać błąd w całej witrynie (wszystkie kontrolery/widoki). – Christoffer

+0

Edytowałem odpowiedź przy użyciu filtra wokół w aplikacji ApplicationController. Czy to dotyczy ciebie? –

+0

Nie mogę przetestować tego inaczej niż przez trzymanie go online przez kilka dni i zobaczenie, czy usuwa on te komunikaty o błędach, ale wydaje się, że działa. Czy istnieje sposób, aby sprowokować TimeoutError, więc mogę go przetestować? – Christoffer

Powiązane problemy