2010-07-22 4 views
53

Delayed :: La fonction d'auto-réessai de Job est géniale, mais il y a une tâche que je souhaite réessayer manuellement maintenant. Y at-il une méthode que je peux appeler sur le travail lui-même comme ...Réessayer manuellement Job dans Delayed_job

Delayed::Job.all[0].perform 

ou de lancer, ou quelque chose. J'ai essayé quelques choses, et j'ai peigné la documentation, mais je n'ai pas compris comment exécuter une nouvelle tentative manuelle d'un travail.

+2

'Delayed :: Worker.new.run (Delayed :: Job.first)' [ref] (http://stackoverflow.com/a/20146200/495132) –

Répondre

88

Pour appeler manuellement un emploi

Delayed::Job.find(10).invoke_job # 10 is the job.id 

Cela ne supprime pas le travail si elle est exécutée avec succès. Vous devez supprimer manuellement:

Delayed::Job.find(10).destroy 
+10

L'alternative proposée par @joe est une solution plus sûre, surtout si le travail a besoin de savoir s'il s'exécute dans un script/console ou dans un job runner. Essayez ceci pour mettre en attente le travail pour une nouvelle tentative immédiate Delayed :: Job.first.update_attributes (: tentatives => 0,: run_at => Heure.maintenant,: failed_at => nil,: locked_by => nil,: locked_at => nil) –

+8

'tentatives' ne peut pas être affecté dans' update_attributes' car il s'agit d'un attribut protégé. Je fais juste: 'dj = Delayed :: Job.first; dj.run_at = Time.now; dj.attempts = 0; dj.save!; ' – Anjan

+0

Pour le faire en masse cela a fonctionné (environ 100 emplois) Delayed :: Job.where.all.each {| dj | dj.run_at = Time.now; dj.attempts = 0; dj.save!} – tobinharris

11

Vous pouvez le faire exactement comme vous l'avez dit, en trouvant le travail et en cours d'exécution.

Cependant, ce que je fais généralement, c'est juste de remettre run_at en arrière pour que le processeur de travail le récupère à nouveau.

+1

Il n'y a pas de méthode 'perform' pour un travail retardé objet. Le plus proche est 'Delayed :: Job.find (10) .payload_object.perform', et on ne devrait pas l'utiliser. – lulalala

8

J'ai une méthode dans un contrôleur à des fins de test qui remet à zéro tout emploi tout retard quand je frappe une URL. Pas super élégant mais fonctionne très bien pour moi:

# For testing purposes 
    def reset_all_jobs 
    Delayed::Job.all.each do |dj| 
     dj.run_at = Time.now - 1.day 
     dj.locked_at = nil 
     dj.locked_by = nil 
     dj.attempts = 0 
     dj.last_error = nil 
     dj.save 
    end 
    head :ok 
    end 
+1

utilise update_all .. c'est un appel à la base de données. – baash05

+1

Vous ne pouvez pas utiliser update_all ebcause les tentatives sont des attributs protégés –

+1

update_all utilise directement SQL et n'appelle donc pas de validations (ou attributs protégés, etc.) – Michael

4

Dans un environnement de développement, par le biais rails console, suite à la suggestion de Joe Martinez, une bonne façon de recommencer tous vos travaux en retard est:

Delayed::Job.all.each{|d| d.run_at = Time.now; d.save!} 
+5

La mise à jour de 'run_at' dans 4.0.1 ne semble pas être suffisante. Je devais faire ce qui suit: 'Delayed :: Job.where (" failed_at n'est pas nul "). Each do | dj | dj.run_at = Time.now; dj.last_error = nil; dj.failed_at = nil; dj.save! fin – steakchaser

6

réponses antérieures ci-dessus pourrait être périmé. J'ai trouvé que je devais mettre failed_at, locked_by et locked_at à zéro:

(pour chaque emploi que vous voulez réessayer):

d.last_error = nil 
d.run_at = Time.now 
d.failed_at = nil 
d.locked_at = nil 
d.locked_by = nil 
d.attempts = 0 
d.failed_at = nil # needed in Rails 5/delayed_job (4.1.2) 
d.save! 
1
Delayed::Job.all.each(&:invoke_job) 
21
Delayed::Worker.new.run(Delayed::Job.last) 

Cela supprimera le travail après sa terminé.

+0

Il va l'enlever même si elle échoue – aledustet

+0

Pour tout le travail retardé, vous pouvez faire Delayed :: Job.find_each (batch_size: 100) {| d | Retardé :: Worker.new.run (d)} ' – MatayoshiMariano

3

si vous avez échoué travail retardé que vous devez ré-exécuter, vous devrez les sélectionner uniquement et régler tout se référer à retry pas null:

Delayed::Job.where("last_error is not null").each do |dj| 
    dj.run_at = Time.now.advance(seconds: 5) 
    dj.locked_at = nil 
    dj.locked_by = nil 
    dj.attempts = 0 
    dj.last_error = nil 
    dj.failed_at = nil 
    dj.save 
end 
0

Mettre cela dans un fichier initialiseur!

module Delayed 
    module Backend 
    module ActiveRecord 
     class Job 
     def retry! 
      self.run_at = Time.now - 1.day 
      self.locked_at = nil 
      self.locked_by = nil 
      self.attempts = 0 
      self.last_error = nil 
      self.failed_at = nil 
      self.save! 
     end 
     end 
    end 
    end 
end 

Ensuite, vous pouvez exécuter Delayed::Job.find(1234).retry!

Ce sera essentiellement coller le travail de nouveau dans la file d'attente et le processus normalement.