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.
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