2013-04-16 4 views
8

Ho iniziato a lavorare con Sidekiq di recente e ho notato che ha una caratteristica impressionante che ho cercato per molto tempo:Ruby on Rails + Sidekiq: Come cambio un orario di inizio del lavoro pianificato?

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

Fondamentalmente posso pianificare un lavoro in futuro, quindi non ho bisogno del mio app per sondare continuamente nuovi eventi con un'ora di inizio.

Ora funziona come un incantesimo, ma come posso cambiare l'ora di inizio di un lavoro? Spesso alcuni eventi programmati avranno il loro orario di inizio cambiato. Come posso replicare questo in sidekiq?

So che posso eliminare il lavoro e crearne uno nuovo, ma è possibile modificare solo l'ora di inizio?

EDIT:

ho costruito su un'idea di Oto Brglez ed ecco il codice documentato:

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) 

Ora, se faccio questo

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

il compito sarà ottenere eseguito in 4 ore e l'altro lavoro (che verrà eseguito in 5 ore) verrà ignorato e rimosso quando raggiunge il suo tempo.

Inizialmente, ho provato a utilizzare Time.now anziché worker.last["payload"]["at"] ma ciò avrebbe potuto essere piuttosto impreciso perché un processo pianificato non verrà sempre eseguito in tempo. Esiste un intervallo di controllo di 15 secondi e se tutti i lavoratori sono occupati altrove, il lavoro potrebbe essere ulteriormente ritardato.

Ho dovuto usare Regexp per abbinare l'ora di inizio perché durante la lettura del task.start avrei potuto ottenere un float con un diverso numero di decimali e la condizione se non passasse. In questo modo ottengo entrambi i valori su 3 decimali.

Ho scoperto che l'unico modo per ottenere l'attributo "at" del lavoro è farlo passare attraverso l'operatore. Se dovessi chiedere a Redis o usare Mike's Sidekiq::ScheduledSet.new, non otterrei il lavoro corrente perché sarebbe già stato estratto da Redis.

EDIT 2:

Per chiunque sia interessato, sono andato con un approccio simile, ma diverso. Fondamentalmente invece di confrontare l'ora di inizio dello Task, ho aggiunto un campo aggiuntivo al modello e alla chiamata Sidekiq, denominata start_token. Se il lavoro sidekiq è stato chiamato con lo stesso token che l'oggetto ha allora è valido, altrimenti scartare e saltare il lavoro. Il token viene aggiornato ogni volta che il modello cambia start_time.

+1

Sulla base della sua seconda modifica, e per coloro che questo può aiutare, come io sto usando un oggetto ActiveRecord dentro il mio lavoro, ho sto usando il campo updated_at. Lo sto passando al mio lavoro con il mio ID ActiveRecord e quando il mio lavoro inizia, controllo se il updated_at è sempre lo stesso – phyzalis

risposta

3

Non penso che modificare/aggiornare i lavori sia la via. Generalmente creo un nuovo lavoro ogni volta che qualcosa cambia. E poi nel lavoro stesso controlla se il tempo per eseguire determinati compiti è giusto ... Se il tempo è giusto, continua con l'attività altrimenti salta semplicemente ...

+0

Punto interessante. Non ci ho pensato. Stai utilizzando l'ora corrente (Time.now) per verificare se il lavoro è quello giusto oppure esiste un modo per ottenere l'ora esatta di inizio del lavoro pianificato? – Oktav

+0

Ho costruito la tua idea e inserirò il mio codice nel corpo della domanda – Oktav

+0

Ok. :) Per il mio scopo il tempo non era un problema. La data era abbastanza. Metti un po 'di codice e vedremo .. –

26

Probabilmente non sta rispondendo alla domanda ma questo è il primo su google per "sidekiq aumenta il tempo di un lavoro già programmato".

Sidekiq ha questo metodo su un lavoro SortedEntry.

Trovare il lavoro:

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

ripianificare il lavoro:

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

Dai a quest'uomo un: birra: – user1262904

+1

Nota: puoi anche vedere quando un determinato lavoro è pianificato per eseguire 'Sidekiq :: ScheduledSet.new.find {criteri} .at'. [La documentazione è qui] (http://www.rubydoc.info/github/mperham/sidekiq/Sidekiq/SortedEntry#at-instance_method) –