2013-04-16 11 views
8

zacząłem pracować z Sidekiq niedawno i zauważyłem, że ma niesamowite funkcję Szukałem przez długi czas:Ruby on Rails + Sidekiq: Jak zmienić zaplanowany czas rozpoczęcia pracy?

UserMailer.delay_until(5.days.from_now).find_more_friends_email 

Zasadniczo mogę zaplanować pracę w przyszłości, więc nie muszę mój aplikacja do ciągłego sondowania nowych wydarzeń z czasem rozpoczęcia.

To działa jak urok, ale jak zmienić czas rozpoczęcia pracy? Często niektóre zaplanowane wydarzenia będą miały zmieniony czas rozpoczęcia. Jak mogę to zreplikować w sidekiq?

Wiem, że mogę usunąć pracę i utworzyć nową, ale czy możliwe jest zmodyfikowanie czasu rozpoczęcia?

EDIT:

I zbudowana na idei OTO Brglez i tutaj jest udokumentowany kod:

module TaskStuff 
    class TaskSetter 
    include Sidekiq::Worker 
    sidekiq_options retry: false 

    def perform(task_id) 
     task = Task.find(task_id) 
     # Get the worker that's performing this job 
     if worker = AppHelpers.find_worker(jid) 
     # If the worker matches the "at" timestamp then this is the right one and we should execute it 
     if worker.last["payload"]["at"].to_s.match(/(\d*\.\d{0,3})\d*/)[1] == task.start.to_f.to_s.match(/(\d*\.\d{0,3})\d*/)[1] 
      task.execute 
     else 
      custom_logger.debug("This worker is the wrong one. Skipping...") 
     end 
     else 
     custom_logger.error("We couldn't find the worker") 
     end 
    end 
    end 
end 


module AppHelpers 

    [...] 

    def self.find_worker(jid) 
    Sidekiq::Workers.new.select {|e| e.last["payload"]["jid"] == jid}.first 
    end 

    [...] 

end 

> task = Task.create(start: 5.hours.from_now) 
> TaskStuff::TastSetter.perform_at(task.start, task.id) 

Teraz, jeśli mogę to zrobić

> task.update_attributes(start: 4.hours.from_now) 
> TaskStuff::TastSetter.perform_at(task.start, task.id) 

zadaniem będzie uzyskać wykonywane w 4 godziny i druga praca (która zostanie wykonana w ciągu 5 godzin) zostanie zignorowana i usunięta, gdy osiągnie swój czas.

Początkowo próbowałem używać Time.now zamiast worker.last["payload"]["at"], ale to mogło być dość niedokładne, ponieważ zaplanowane zadanie nie zawsze zostanie wykonane na czas. Istnieje interwał kontrolny wynoszący 15 sekund, a jeśli wszyscy pracownicy są zajęci w innym miejscu, praca może zostać opóźniona.

Musiałem użyć Regexp do dopasowania czasu rozpoczęcia, ponieważ podczas czytania task.start mógłbym uzyskać zmiennoprzecinkowe z inną liczbą miejsc po przecinku, a warunek jeśli nie przejdzie. W ten sposób otrzymuję obie wartości do 3 dziesiętnych.

Odkryłem, że jedynym sposobem uzyskania atrybutu "at" jest przeniesienie go przez pracownika. Gdybym poprosił Redisa lub użył Mike'a Sidekiq::ScheduledSet.new, nie dostałbym obecnej pracy, ponieważ zostałby on już wyciągnięty z Redis.

EDIT 2:

Dla wszystkich zainteresowanych, poszedłem z podobnym ale innego podejścia. Zasadniczo zamiast porównywania czasu początkowego Task, dodałem dodatkowe pole do modelu i wywołanie w Sidekiq, o nazwie start_token. Jeśli zadanie sidekiq zostało wywołane z tym samym tokenem, że obiekt ma to jest ważne, w przeciwnym razie odrzuć i pomiń zadanie. Token jest aktualizowany za każdym razem, gdy model zmienia czas rozpoczęcia.

+1

Na podstawie swojej drugiej edycji, a dla tych, którzy mogą w tym pomóc, ponieważ używam obiektu ActiveRecord wewnątrz mojej pracy, ja używam pola updated_at. Przekazuję go do mojej pracy z moim identyfikatorem ActiveRecord i kiedy zaczyna się moje zadanie, sprawdzam, czy updated_at jest wciąż ten sam – phyzalis

Odpowiedz

3

Nie sądzę, że praca nad edycją/aktualizacją jest drogą. Zwykle tworzę nową pracę za każdym razem, gdy coś się zmienia. A następnie w samym zadaniu sprawdź, czy czas wykonania określonego zadania jest prawidłowy ... Jeśli czas jest właściwy, kontynuuj wykonywanie zadania, w przeciwnym razie po prostu pomiń ...

+0

Interesujący punkt. Nie myślałem o tym. Czy używasz bieżącego czasu (Time.now), aby sprawdzić, czy zadanie jest właściwe, czy też istnieje sposób, aby uzyskać dokładny czas rozpoczęcia zaplanowanego zadania? – Oktav

+0

Zbudowałem na twoim pomyśle i będę umieszczał mój kod w pytaniu ciało – Oktav

+0

Ok. :) Dla mojego celu czas nie był problemem. Data była wystarczająca. Wpisz kod, a my zobaczymy ... –

26

Prawdopodobnie nie odpowiada na pytanie, ale jest to pierwsze w google dla "sidekiq zwiększyć czas już zaplanowanej pracy".

Sidekiq ma tę metodę w zadaniu SortedEntry.

Znajdź pracę:

job = Sidekiq::ScheduledSet.new.find_job(job_id) 

przełożyć pracy:

job.reschedule(Time.now + 2.hours) 
+1

Podaj tego mężczyznę: piwo: – user1262904

+1

Uwaga możesz również zobaczyć, kiedy zaplanowane jest wykonanie określonego zadania, wykonując 'Sidekiq :: ScheduledSet.new.find {criteria} .at'. [Dokumentacja jest tutaj] (http://www.rubydoc.info/github/mperham/sidekiq/Sidekiq/SortedEntry#at-instance_method) –