5

Qualche idea su come ottenere l'ID Delayed::Job da ActiveJob per l'accodamento? Quando accodico un lavoro torno a un'istanza di ActiveJob::Base con un @job_id, ma quell'ID lavoro sembra essere interno a ActiveJob. La mia ipotesi migliore è finora solo camminare per i posti di lavoro di più recente istituzione:Rails 4.2 ottiene un ID lavoro ritardato dal lavoro attivo

active_job_id = GenerateReportJob.perform_later(self.id).job_id 
delayed_job = Delayed::Job.order(id: :desc).limit(5).detect do |job| 
    YAML.load(job.handler).job_data['job_id'] == active_job_id 
end 

ma che sembra tutti i tipi di hacky. Un po 'sorpreso ActiveJob non restituisce l'ID da Delayed::Job, soprattutto perché è ciò che viene esplicitamente restituito quando il lavoro viene messo in coda.

== EDIT

Sembra che io non sono l'unico (https://github.com/rails/rails/issues/18821)

+0

Ah, ma poi alcuni potrebbero sostenere che la necessità di ottenere l'id del lavoro è "tutti i tipi di hacky" anche! Per curiosità e perché potrebbe aprire la porta a un approccio alternativo, perché hai bisogno del posto di lavoro? – Shadwell

+2

È per la possibilità di annullare i report prima che vengano eseguiti mentre sono in coda. – kddeisz

risposta

6

Nel caso in cui qualcuno trova questo in futuro: Rails appena accettato una patch per consentire di ottenere questo id da provider_job_id in Rails 5. È possibile farlo funzionare con una patch come

ActiveJob::QueueAdapters::DelayedJobAdapter.singleton_class.prepend(Module.new do 
    def enqueue(job) 
    provider_job = super 
    job.provider_job_id = provider_job.id 
    provider_job 
    end 

    def enqueue_at(job, timestamp) 
    provider_job = super 
    job.provider_job_id = provider_job.id 
    provider_job 
    end 
end) 
+0

Grazie per aver postato la risposta! Dove si metterebbe questo codice, però? – Alexander

+0

@Alexander Tipicamente questo andrebbe in un inizializzatore. Qualcosa come config/initializers/delayed_job.rb – kddeisz

+0

Prima che arrivasse la patch, mi sono imbattuto in questo problema, e ho creato una gemma per interrogare lo stato dei lavori tramite ActiveJob: https://github.com/cdale77/active_job_status –

0

Invece di rimuovere il processo dalla coda, se viene annullata si potrebbe modellare una cancellazione del lavoro stesso.

Quindi, quando si arriva a eseguire il GenerateReportJob è possibile prima verificare la cancellazione del rapporto. Se ce n'è uno, puoi distruggere il record di cancellazione e abbandonare la generazione del rapporto. Se non ci sono cancellazioni, puoi continuare normalmente.

+0

Sì, potrei. Ma ... il punto di usare Delayed :: Job è che è un discendente di ActiveRecord :: Base. Ha un id sul tavolo - quindi sembra sciocco creare un'altra colonna/modello/oggetto/concetto di cancellazione quando prima di integrarmi con il lavoro attivo sono riuscito a ottenere l'id. – kddeisz

+0

Comunque, il punto di porre questa domanda era solo per vedere se qualcuno sapeva come ottenere l'ID. Guardando qui però: (https://github.com/rails/rails/blob/master/activejob/lib/active_job/enqueuing.rb#L74) sembra indicare che quel lavoro verrà restituito in entrambi i modi, al contrario del ritardo lavoro. E così lo farò. – kddeisz

+0

Sì, mi dispiace, ho apprezzato che stavo rispondendo a una domanda leggermente diversa. – Shadwell

2

ho fatto funziona in Rails 4.2 utilizzando la nuova patch da Rails 5 in questo modo:

creare il file lib/active_job/queue_adapters/delayed_job_adapter.rb

module ActiveJob 
    module QueueAdapters 
    class DelayedJobAdapter 
     class << self 
     def enqueue(job) #:nodoc: 
      delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name) 
      job.provider_job_id = delayed_job.id 
      delayed_job 
     end 

     def enqueue_at(job, timestamp) #:nodoc: 
      delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name, run_at: Time.at(timestamp)) 
      job.provider_job_id = delayed_job.id 
      delayed_job 
     end 
     end 

     class JobWrapper #:nodoc: 
     attr_accessor :job_data 

     def initialize(job_data) 
      @job_data = job_data 
     end 

     def perform 
      Base.execute(job_data) 
     end 
     end 
    end 
    end 
end 
3

Ispirato alla risposta di Beguené e qualche rovescio engineering del codice ActiveJob Rails 5, ho fatto lavorare con Rails 4.2 da

1) aggiungendo seguente codice nel lib/active_job/queue_adapters/delayed_job_adapter.rb o config/initializers/delayed_job.rb (entrambe le posizioni hanno lavorato):

# file: lib/active_job/queue_adapters/delayed_job_adapter.rb 
module ActiveJob 
    module Core 
    # ID optionally provided by adapter 
    attr_accessor :provider_job_id 
    end 

    module QueueAdapters 
    class DelayedJobAdapter 
     class << self 
     def enqueue(job) #:nodoc: 
      delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name) 
      job.provider_job_id = delayed_job.id 
      delayed_job 
     end 

     def enqueue_at(job, timestamp) #:nodoc: 
      delayed_job = Delayed::Job.enqueue(JobWrapper.new(job.serialize), queue: job.queue_name, run_at: Time.at(timestamp)) 
      job.provider_job_id = delayed_job.id 
      delayed_job 
     end 
     end 
     class JobWrapper #:nodoc: 
     attr_accessor :job_data 

     def initialize(job_data) 
      @job_data = job_data 
     end 

     def perform 
      Base.execute(job_data) 
     end 
     end 
    end 
    end 
end 

La dichiarazione attr_accessor :provider_job_id è necessario in Rails 4.2, poiché è utilizzato nel metodo di accodamento e non è ancora definito in 4.2.

Poi possiamo fare uso di esso come segue:

2) definire la nostra propria classe ActiveJob:

# file: app/jobs/my_job.rb 
class MyJob < ActiveJob::Base 
    queue_as :default 

    def perform(object, performmethod = method(:method)) 
    # Do something later 
     returnvalue = object.send(performmethod) 
     returnvalue 
    end 

    end 
end 

3) Ora possiamo creare un nuovo lavoro in qualsiasi parte del codice:

job = MyJob.perform_later(Myobject, "mymethod") 

Inserirà il metodo Myobject.mymethod nella coda.

4) Il codice in 1) ci aiuta a trovare il lavoro in ritardo che è associato con il nostro lavoro:

delayed_job = Delayed::Job.find(job.provider_job_id) 

5), infine, si può fare, tutto ciò che dobbiamo fare con il delayed_job, per esempioeliminarlo:

delayed_job.delete 

Nota: in Rails 5, punto 1) non sarà più necessario, dal momento che lo stesso codice esatto è parte integrante di Rails 5.

+0

Questo funziona già nella risposta accettata. – kddeisz

+0

@kddeisz: Ho testato solo la risposta di Beguene (perché è più vicina al codice di Rails 5 e la tua risposta è stata troppo intelligente per me da capire, ma sembra grandiosa!). Nella risposta di Beguene, mancava solo un ingrediente minuscolo: l'istruzione '' 'attr_accessor: provider_job_id'''. L'opzione migliore sarebbe stata quella di aggiungere un commento alla risposta di Beguene, ma, poiché sono nuovo nello stackoverflow e non ho alcuna reputazione, non avevo il permesso di aggiungere commenti. Pertanto, ho capito, ha senso rispondere alla domanda con tutti gli ingredienti di cui avevo bisogno per farlo funzionare. – Olli

+0

Questo è bello, se si desidera ottenere l'id del provider (id del lavoro ritardato) nei callback 'enqueue', ma non fornisce l'id al momento dell'esecuzione (nei callback' perform') – phil