2015-02-17 25 views
5

Ich verwende Rails 4.2 und verzögertes_job 4.0.6 als mein ActiveJob-Backend.In Rails 4.2 überprüfen, ob ein Job bereits eingereiht ist

Ich habe einen Job, den ich nur einmal in der Warteschlange zulassen möchte. Der betreffende Job benötigt eine Minute zum Ausführen. Es wird durch einen Callback für ein Modell in die Warteschlange eingereiht. Der Rückruf wird viel häufiger ausgelöst, als der Job abgeschlossen werden kann. Der Job muss nicht mehr als einmal in der Warteschlange stehen.

Hier ist ein Pseudocode für das, was ich erreichen möchte.

Wenn eine Instanz des Jobs ausgeführt wird, wenn er erneut aufgerufen wird, sollte er für die Zukunft in die Warteschlange eingereiht werden. Ich suche nach einer Möglichkeit, den Job für einen zukünftigen Lauf maximal 1 Mal in die Warteschlange zu stellen.

Ich nehme an, dass die Antwort speziell für delayed_job sein muss, aber wenn sie auf ActiveJob verallgemeinert werden kann, wäre das sogar noch besser.

+0

Können Sie redis verwenden? Wie in, hast du es auf deinem Stack installiert? –

+0

Ich muss bei diesem Projekt bei Postgres bleiben. –

+0

Sie werden nicht aufgefordert, es zu ersetzen, aber wenn Sie redis zusammen mit Postgres verwenden können, kann es eine einfache Lösung geben. –

Antwort

2

Dies kann nicht die genaue Passform sein, aber es sollte Sie in die richtige Richtung erhalten zeigte:

def self.up 
    create_table :delayed_jobs, :force => true do |table| 
    table.integer :priority, :default => 0, :null => false 
    table.integer :attempts, :default => 0, :null => false 
    table.text  :handler,     :null => false 
    table.text  :last_error 
    table.datetime :run_at 
    table.datetime :locked_at 
    table.datetime :failed_at 
    table.string :locked_by 
    table.string :queue 
    table.timestamps 
end 

So haben Sie eine Statusspalte zu dieser Tabelle hinzufügen könnte, dann eine Abfrage ausführen, wie dies zu greifen den Job und überprüfen Sie seinen Status, bevor Sie etwas anderes tun.

Delayed::Job.where(queue: '<YOUR QUEUE>').where(id: params[:id]).status

Wie würden Sie den Status gesetzt, fragen Sie? Nun, verwenden Sie den Erfolgshaken in verzögerten Jobs. Es würde ungefähr so ​​aussehen:

def success(job) 
    update_status('success') 
end 

private 

def update_status(status) 
    job = Job.find job_id 
    job.status = status 
    job.save! 
end 

Hoffe, das hilft!

+0

Ich versuche es. –

1

Ich poste, was ich als Antwort getan habe, um ein Feedback zu bekommen. Dies ist nur eine mögliche Lösung, die ich teste.

Im Job überprüfe ich die Delayed :: Job-Liste, um zu sehen, ob der aktuelle Handler vorhanden ist. Wenn es ist, überspringe ich den Job.

# queue_job.rb 
class EnqueueJob < ActiveJob::Base 
    queue_as :default 

    def already_enqueued? 
    Delayed::Job.all.any? do |job| 
     job.handler.include?("EnqueueJobHandler") 
    end 
    end 

    def perform 
    unless already_enqueued? 
     # do stuff 
    end 
    end 
end 

Bisher hält es den Job davon ab, die Warteschlange zu überholen. Der Nachteil ist, dass ich nicht weiß, dass ich den Cache so aktuell halte, wie ich es möchte.

0

Das könnte zu einfach sein, aber warum nicht einfach eine Klassenvariable hinzufügen, sagen @@running, setzen sie true auf before_enqueue und löschen Sie es am Ende des Jobs?

Dann können Sie einfach nach dieser Variable suchen und die Enqueue überspringen, wenn sie gesetzt ist.

Verwandte Themen