2014-04-03 11 views
5

Mam pracownika sidekiq, który nie powinien zająć więcej niż 30 sekund, ale po kilku dniach stwierdzę, że cała kolejka roboczy przestaje działać, ponieważ wszystkie pracownicy są zamknięci.Pracownik Sidekiq działa przez tysiące sekund, mimo że istnieje limit czasu

Oto mój pracownik:

class MyWorker 
    include Sidekiq::Worker 
    include Sidekiq::Status::Worker 
    sidekiq_options queue: :my_queue, retry: 5, timeout: 4.minutes 

    sidekiq_retry_in do |count| 
    5 
    end 

    sidekiq_retries_exhausted do |msg| 
    store({message: "Gave up."}) 
    end 

    def perform(id) 
    begin 
     Timeout::timeout(3.minutes) do 
     got_lock = with_semaphore("lock_#{id}") do 
      # DO WORK 
     end 
     end 
    rescue ActiveRecord::RecordNotFound => e 
     # Handle 
    rescue Timeout::Error => e 
     # Handle 
     raise e 
    end 
    end 

    def with_semaphore(name, &block) 
    Semaphore.get(name, {stale_client_timeout: 1.minute}).lock(1, &block) 
    end 
end 

A semafor klasa używamy. (Redis-semafor gem)

class Semaphore 
    def self.get(name, options = {}) 
    Redis::Semaphore.new(name.to_sym, 
     :redis => Application.redis, 
     stale_client_timeout: options[:stale_client_timeout] || 1.hour, 
    ) 
    end 
end 

Zasadniczo będę zatrzymać pracownika i będzie State zrobione: 10000 sekund, które pracownik powinien zostać uruchomione za NIGDY.

Ktoś ma jakieś pomysły, jak to naprawić lub co jest przyczyną? Pracownicy pracują na maszynie EngineYard.

Edytuj: Jeden dodatkowy komentarz. # DO WORK ma szansę wystrzelić funkcję PostgresSQL. Zauważyłem w dziennikach niektóre wzmianki o PG :: TRDeadlockDetected: ERROR: wykryto zakleszczenie. Czy to spowodowałoby, że robotnik nigdy się nie ukończy, nawet przy ustawionym limicie czasu?

+0

Czy jest jakiś konkretny powód, dlaczego używasz blokady Semafor wewnątrz „Perform” metody pracownika? Pytam o to, ponieważ uważam, że ta mieszanka Sidekiq + Locking jest nieco niebezpieczna. [Ludzie Sidekiq polecają] (https://github.com/mperham/sidekiq/wiki/Best-Practices) prace powinny być jak najbardziej odizolowane, więc nie ma żadnych wąskich gardeł ani potencjalnych zakleszczeń, które mogą się zdarzyć, blokując rzeczy podczas #perform –

+0

W połączeniu z sidetiq zauważam, że czasami ten sam identyfikator zostanie wrzucony do kolejki do przetworzenia, co zapobiega dwukrotnemu przetworzeniu. – Geesu

Odpowiedz

1

Biorąc chcesz zapewnić unikalne wykonanie pracy, i będzie próbował usunięcie wszystkich blokad i przekazać unikatowości kontrolę pracy do wtyczki jak Sidekiq Unique Jobs

W tym przypadku, nawet jeśli sidetiq enqueue ten sam identyfikator stanowiska dwukrotnie, ten plugin, zapewnia będzie on zapisywany/przetwarzany jednorazowo.

+0

Czy uważasz, że problemem jest redis-semaphore? Nadal nie rozumiem, dlaczego limit czasu zostałby zignorowany. – Geesu

0

Można również spróbować ActiveRecord with_lock mechanizm: http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html

+0

Podejrzewam, że to może być prawdziwa przyczyna problemu: http://blog.headius.com/2008/02/rubys-threadraise-threadkill-timeoutrb.html – Geesu

+0

Ach, tak, to wygląda bardzo podobnie. Uwaga dla siebie, nie timeout z blokadą bazy danych. Czy jest jakiś powód, dla którego potrzebujesz, aby przerwać? Może istnieje sposób na przełamanie logiki, aby umożliwić dostęp do rekordu pomiędzy. – lobati

+0

btw, powinieneś rozważyć udzielenie odpowiedzi na własne pytanie. – lobati