Si vous consultez cela sur https://github.com/collectivedea/delayed_job, vous lisez la documentation de la branche principale. Afficher la documentation pour la dernière version (4.1.13).
Retard :: Job (ou DJ) résume le modèle commun d'exécuter de manière asynchrone des tâches plus longues en arrière-plan.
Il s'agit d'une extraction directe de Shopify où le tableau des travaux est responsable d'une multitude de tâches de base. Parmi ces tâches, il y a:
Envoi d'énormes newsletters
redimensionnement de l'image
téléchargements http
Mise à jour des collections intelligentes
Mise à jour de SOLR, notre serveur de recherche, après les modifications du produit
importations par lots
chèques de spam
Suivez-nous sur Twitter pour obtenir des mises à jour et des avis sur les nouvelles versions.
Delayed_job 3.0.0 ne prend en charge que Rails 3.0+.
Delayed_job prend en charge plusieurs backends pour stocker la file d'attente de travaux. Voir le wiki pour d'autres backends.
Si vous prévoyez d'utiliser Delayed_Job avec un enregistrement actif, ajoutez delayed_job_active_record
à votre Gemfile
.
gem 'retardé_job_active_record'
Si vous prévoyez d'utiliser Delayed_job avec mongoid, ajoutez delayed_job_mongoid
à votre Gemfile
.
gem 'retardé_job_mongoïde'
Exécutez bundle install
pour installer le backend et les gemmes de retard.
Le backend enregistré actif nécessite un tableau des travaux. Vous pouvez créer ce tableau en exécutant la commande suivante:
rails generate delayed_job:active_record rake db:migrate
Pour Rails 4.2+, voir ci-dessous
En mode développement, si vous utilisez Rails 3.1+, votre code d'application rechargera automatiquement tous les 100 travaux ou lorsque la file d'attente se terminera. Vous n'avez plus besoin de redémarrer le travail retardé chaque fois que vous mettez à jour votre code en développement.
Dans Rails 4.2+, définissez la file d'attente_adapter dans config / application.rb
config.active_job.queue_adapter =: retardé_job
Voir le Guide des Rails pour plus de détails.
Si vous utilisez le GEM Protected_attributes, il doit apparaître avant Delayed_Job dans votre gemfile. Si vos travaux échouent avec:
ActiveRecord::StatementInvalid: PG::NotNullViolation: ERROR: null value in column "handler" violates not-null constraint
Ensuite, c'est le correctif que vous recherchez.
Le travail retardé 3.0.0 introduit une nouvelle colonne au tableau de retard.
Si vous améliorez le travail retardé 2.x, exécutez le générateur de mise à niveau pour créer une migration pour ajouter la colonne.
rails generate delayed_job:upgrade rake db:migrate
Appelez .delay.method(params)
sur n'importe quel objet et il sera traité en arrière-plan.
# Sans retardé[email protected]! (@ Device) # avec retardé[email protected]! (@ Device)
Si une méthode doit toujours être exécutée en arrière-plan, vous pouvez appeler #handle_asynchronously
après la déclaration de la méthode:
dispositif de classe Def délivre # Méthode de longue course fin handle_asynchronely: DeliverDdevice = Device.newdevice.deliver
#handle_asynchronously
et #delay
prenez ces paramètres:
:priority
(numéro): les nombres inférieurs s'exécutent en premier; La valeur par défaut est 0 mais peut être reconfigurée (voir ci-dessous)
:run_at
(temps): exécutez le travail après cette période (probablement à l'avenir)
:queue
(String): Nommé la file d'attente pour mettre ce travail, une alternative aux priorités (voir ci-dessous)
Ces paramètres peuvent être des objets proc, permettant une évaluation du temps d'appel de la valeur.
Par exemple:
Longtes de classe def send_mailer # un autre code fin handle_asynchronely: send_mailer ,: priority => 20 def in_the_future # un autre code fin # 5.MINUTES.FROM_NOW sera évalué lorsque IN_THE_FUTURE est appelé handle_asynchronely: in_the_future ,: run_at => proc.new {5.minutes.from_now} def self.when_to_run2.hours.from_now fin classe << selfdef call_a_class_method # un autre codeendhandle_asynchronely: call_a_class_method,: run_at => proc.new {when_to_run} fin att_reader: how_important def call_an_instance_method # un autre code fin handle_asynchronely: call_an_instance_method ,: priority => proc.new {| i | I.How_Important} fin
Si jamais vous souhaitez appeler une méthode handle_asynchronously
'D sans travail retardé, par exemple tout en débogues quelque chose sur la console, ajoutez simplement _without_delay
au nom de la méthode. Par exemple, si votre méthode d'origine était foo
, appelez foo_without_delay
.
Le travail retardé utilise une syntaxe spéciale pour les envoyes de rails. N'appelez pas la méthode .deliver
lorsque vous utilisez .delay
.
# sans retard_jobnotifier.signup (@user) .deliver # avec retardé_jobnotifier.delay.signup (@user) # de retard_job fonctionnant à un timenotificier spécifique. , la méthode .with doit être appelée avant le .delay méthodyNotifier.with (foo: 1, bar: 2) .delay.signup (@user)
Vous pouvez également envisager d'utiliser un travail actif avec Action Mailer qui fournit une syntaxe pratique .deliver_later
qui transmet à un emploi retardé sous le capuchon.
DJ 3 présente des files d'attente nommées de style resque tout en conservant la priorité de style DJ. L'objectif est de fournir un système pour le groupe de tâches à travailler par des pools séparés de travailleurs, qui peuvent être mis à l'échelle et contrôlés individuellement.
Les travaux peuvent être attribués à une file d'attente en définissant l'option de queue
:
object.delay (: queue => 'suivi'). MethodDelayed :: job.enqueue job ,: queue => 'suivi'handle_asynchronely: tweet_later ,: queue =>' tweets '
Vous pouvez configurer les priorités par défaut pour les files d'attente nommées:
Retardé :: wearch.queue_attributes = { high_priority: {priority: -10}, Low_priority: {prioritaire: 10}}
Les priorités de file d'attente configurées peuvent être remplacées en passant la priorité à la méthode de retard
object.delay (: file d'attente => 'high_priority', priorité: 0) .Method
Vous pouvez démarrer des processus pour ne faire que certaines files d'attente avec les options queue
et queues
définies ci-dessous. Les processus démarrés sans spécifier une file d'attente exécuteront des travaux à partir de toute file d'attente. Pour avoir efficacement un processus qui exécute des travaux lorsqu'une file d'attente n'est pas spécifiée, définissez un nom de file d'attente par défaut avec Delayed::Worker.default_queue_name
et demandez aux processus d'exécuter cette file d'attente.
script/delayed_job
peut être utilisé pour gérer un processus d'arrière-plan qui commencera à travailler sur des travaux.
Pour ce faire, ajoutez gem "daemons"
à votre Gemfile
et assurez-vous que vous avez exécuté rails generate delayed_job
.
Vous pouvez ensuite effectuer ce qui suit:
RAILS_ENV=production script/delayed_job start RAILS_ENV=production script/delayed_job stop # Runs two workers in separate processes. RAILS_ENV=production script/delayed_job -n 2 start RAILS_ENV=production script/delayed_job stop # Set the --queue or --queues option to work from a particular queue. RAILS_ENV=production script/delayed_job --queue=tracking start RAILS_ENV=production script/delayed_job --queues=mailers,tasks start # Use the --pool option to specify a worker pool. You can use this option multiple times to start different numbers of workers for different queues. # The following command will start 1 worker for the tracking queue, # 2 workers for the mailers and tasks queues, and 2 workers for any jobs: RAILS_ENV=production script/delayed_job --pool=tracking --pool=mailers,tasks:2 --pool=*:2 start # Runs all available jobs and then exits RAILS_ENV=production script/delayed_job start --exit-on-complete # or to run in the foreground RAILS_ENV=production script/delayed_job run --exit-on-complete
Rails 4: Remplacez le script / retardé_job par bin / retardé_job
Les travailleurs peuvent s'exécuter sur n'importe quel ordinateur, tant qu'ils ont accès à la base de données et que leur horloge est synchronisée. Gardez à l'esprit que chaque travailleur vérifiera la base de données au moins toutes les 5 secondes.
Vous pouvez également invoquer rake jobs:work
qui commencera à travailler sur des emplois. Vous pouvez annuler la tâche Rake avec CTRL-C
.
Si vous souhaitez simplement exécuter tous les travaux disponibles et sortir, vous pouvez utiliser rake jobs:workoff
Travaillez les files d'attente en définissant la variable d'environnement QUEUE
ou QUEUES
.
QUEUE=tracking rake jobs:work QUEUES=mailers,tasks rake jobs:work
La syntaxe suivante redémarrera les travaux retardés:
RAILS_ENV=production script/delayed_job restart
Pour redémarrer plusieurs travailleurs de retard_job:
RAILS_ENV=production script/delayed_job -n2 restart
Rails 4: Remplacez le script / retardé_job par bin / retardé_job
Les travaux sont des objets rubis simples avec une méthode appelée performance. Tout objet qui réagit pour effectuer peut être fourré dans la table des travaux. Les objets de travail sont sérialisés en YAML afin qu'ils puissent plus tard être ressuscités par le Runner.
NewsletterJob = struct.new (: text ,: e-mail) faire def PerformEmails.each {| e | Newslettermailer.deliver_text_to_email (texte, e)} endenddelayed :: job.enqueue newsletterjob.new ('lorem ipsum ...', client.Pluck (: e-mail))
Pour définir une tentative maximale par emploi qui remplace le retard :: wearch.max_attempts Vous pouvez définir une méthode max_attempts au travail
NewsletterJob = struct.new (: text ,: e-mail) faire def PerformEmails.each {| e | Newslettermailer.deliver_text_to_email (texte, e)} fin def max_attempts3 renforcer
Pour définir un temps d'exécution maximum par travail qui remplace la retard :: wearch.max_run_time, vous pouvez définir une méthode max_run_time au travail
Remarque: Cela ne peut être utilisé que pour définir un max_run_time qui est inférieur à celui de retard :: wearch.max_run_time. Sinon, le verrou sur le travail expirerait et un autre travailleur commencerait le travail sur le travail en cours.
NewsletterJob = struct.new (: text ,: e-mail) faire def PerformEmails.each {| e | Newslettermailer.deliver_text_to_email (texte, e)} fin def max_run_time120 # secondes renforcer
Pour définir une valeur par défaut par emploi pour la destruction de travaux défaillants qui remplacent le retard :: worker.destroy_failed_jobs Vous pouvez définir un destrust_failed_jobs? Méthode au travail
NewsletterJob = struct.new (: text ,: e-mail) faire def PerformEmails.each {| e | Newslettermailer.deliver_text_to_email (texte, e)} fin de destrust_failed_jobs? False renforcer
Pour définir un nom de file d'attente par défaut pour un travail personnalisé qui remplace :: worker.default_queue_name, vous pouvez définir une méthode de queue_name sur le travail
NewsletterJob = struct.new (: text ,: e-mail) faire def PerformEmails.each {| e | Newslettermailer.deliver_text_to_email (texte, e)} fin def queue_name'newsletter_queue ' renforcer
Sur l'erreur, le travail est à nouveau planifié en 5 secondes + n ** 4, où n est le nombre de tentatives. Vous pouvez définir votre propre méthode reschedule_at
pour remplacer ce comportement par défaut.
NewsletterJob = struct.new (: text ,: e-mail) faire def performMails.each {| e | Newslettermailer.deliver_text_to_email (texte, e)} fin def reprodules_at (current_time, tentatives) current_time + 5.seconds renforcer
Vous pouvez définir des crochets à votre travail qui seront appelés à différentes étapes du processus:
Remarque: Si vous utilisez ActiveJob, ces crochets ne sont pas disponibles pour vos travaux. Vous devrez utiliser les rappels d'ActiveJob. Vous pouvez trouver des détails ici https://guides.rubyonrails.org/active_job_basics.html#callbacks
classe ParanoidNewSletterJob <newsletterjob def enqueue (travail) record_stat 'newsletter_job / enque' fin def PerformEmails.each {| e | Newslettermailer.deliver_text_to_email (texte, e)} fin Def avant (Job) Record_stat 'newsletter_job / start' fin Def après (travail) enregistre_stat 'newsletter_job / après' fin Def Success (Job) Record_stat 'Newsletter_Job / Success' fin ERROR DEF (travail, exception) Airbrake.notify (exception) fin défaillance (travail) page_sysadmin_in_the_middle_of_the_night renforcer
La bibliothèque tourne autour d'un tableau de retard_jobs qui ressemble comme suit:
Create_Table: Delayed_Jobs ,: Force => true do | Table | table.integer: priorité,: par défaut => 0 # permet à certains travaux de sauter vers l'avant de la file d'attente Table.Integer: Tentatives ,: Default => 0 # fournit des tentatives, mais échoue toujours. Table.Text: gestionnaire # chaîne codée par YAML de l'objet qui fonctionnera Table.Text: Last_error # Raison du dernier échec (voir note ci-dessous) table.dateTime: run_at # quand s'exécuter. Pourrait être le temps.zone. maintenant pour immédiatement, ou dans le futur. Table.DateTime: Locked_at # Définissez lorsqu'un client travaille sur cet objet table.datetime: défaillance_at # set lorsque toutes les tentatives ont échoué (en fait, par défaut, l'enregistrement est supprimé à la place) Table.String: Locked_By # qui travaille sur cet objet (s'il est verrouillé) table.string: file d'attente # le nom de la file d'attente table.Timestampsend
Sur l'erreur, le travail est à nouveau planifié en 5 secondes + n ** 4, où n est le nombre de tentatives ou en utilisant la méthode reschedule_at
du travail.
Le Worker.max_attempts
par défaut est 25. Après cela, le travail est supprimé (par défaut), soit laissé dans la base de données avec le jeu "Faillit_at". Avec la valeur par défaut de 25 tentatives, la dernière réessayer sera 20 jours plus tard, le dernier intervalle étant de près de 100 heures.
Le Worker.max_run_time
par défaut est 4.hours. Si votre travail prend plus de temps que cela, un autre ordinateur pourrait le récupérer. C'est à vous de vous assurer que votre travail ne dépasse pas cette fois. Vous devriez le définir sur le plus longtemps que vous pensez que le travail pourrait prendre.
Par défaut, il supprimera les travaux ratés (et il supprime toujours des travaux réussis). Si vous souhaitez conserver des emplois échoués, définissez Delayed::Worker.destroy_failed_jobs = false
. Les travaux échoués seront marqués de non-nuls défaillants_at.
Par défaut, tous les travaux sont planifiés avec priority = 0
, ce qui est la priorité absolue. Vous pouvez modifier cela en définissant Delayed::Worker.default_priority
en autre chose. Les nombres plus faibles ont une priorité plus élevée.
Le comportement par défaut consiste à lire 5 travaux de la file d'attente lors de la recherche d'un emploi disponible. Vous pouvez configurer cela en définissant Delayed::Worker.read_ahead
.
Par défaut, tous les travaux seront mis en file d'attente sans file d'attente nommée. Une file d'attente nommée par défaut peut être spécifiée à l'aide Delayed::Worker.default_queue_name
.
Si aucun emploi n'est trouvé, le travailleur dort pendant la durée spécifiée par l'option de retard de sommeil. Réglez Delayed::Worker.sleep_delay = 60
pour un temps de sommeil de 60 secondes.
Il est possible de désactiver les travaux retardés à des fins de test. Delayed::Worker.delay_jobs = false
pour exécuter tous les travaux en temps réel.
Ou Delayed::Worker.delay_jobs
peut être un proc qui décide d'exécuter des emplois en ligne sur une base par emploi:
Retardé :: worker.delay_jobs = -> (travail) { job.Queue! = 'inline'}
Vous devrez peut-être augmenter les exceptions sur les signaux SIGTERM, Delayed::Worker.raise_signal_exceptions = :term
amènera le travailleur à soulever une SignalException
ce qui entraînera une déverrouillage du travail de course et d'être déverrouillé, ce qui rend le travail à la disposition d'autres travailleurs. La valeur par défaut de cette option est fausse.
Voici un exemple de modification des paramètres du travail dans les rails:
# config / initialisers / Delayed_job_config.rbdelayed :: wearch.destroy_failed_jobs = falSelayed :: worker.sleep_delay = 60delayed :: wearch.max_atempts = 3delayed :: wearch.max_run_timed: workerdelded: working.read_ahead) nom = 'default'delayed :: worker.delay_jobs =! rails.env.test? Delayed :: worker.raise_signal_exceptions =: termdelayed :: worker.logger = logger.new (file.join (rails.root,' log '', ' Delayed_job.log '))
Vous pouvez invoquer rake jobs:clear
pour supprimer tous les emplois dans la file d'attente.
Les bons endroits pour obtenir de l'aide sont:
Groupes Google où vous pouvez rejoindre notre liste de diffusion.
Stackoverflow