Docs · Guides

Tâches en arrière-plan.

Le travail qui ne doit pas faire attendre un visiteur : synchroniser des stocks, envoyer des courriels, redimensionner des images. Sur Canner, un projet exécute un seul processus; le plus simple est donc une file de tâches conservée dans votre base Postgres, qui s’exécute à l’intérieur de ce processus. Cette page le montre avec Rails et GoodJob.

Exécuter la file dans le processus web

GoodJob conserve les tâches dans votre base Canner et, en mode async, les exécute dans des fils du serveur Rails lui-même. C’est la configuration que Rails et GoodJob recommandent pour un seul serveur, et elle n’exige rien d’autre de Canner : les tâches utilisent le même code, les mêmes variables d’environnement et la même base que l’app web, et redémarrent avec elle.

# config/environments/production.rb  (or set GOOD_JOB_EXECUTION_MODE=async)
config.active_job.queue_adapter = :good_job
config.good_job.execution_mode = :async   # jobs run in threads of the web process
config.good_job.max_threads = 3

Ajoutez le gem good_job, lancez son générateur pour obtenir la migration, et appliquez-la avec votre commande de mise en production :

bundle exec rails db:migrate

Les tâches démarrent dès qu’elles sont mises en file : GoodJob est avisé des nouvelles tâches par Postgres, sans délai d’interrogation. Dans nos essais sur Canner, les tâches démarraient en quelques dizaines de millisecondes, et 200 tâches mises en file d’un coup se sont exécutées chacune exactement une fois.

Connexions à la base de données

Le DATABASE_URL de votre app donne à chaque connexion sa propre session Postgres. Ce qui exige une session — verrous consultatifs, LISTEN/NOTIFY, requêtes préparées, SET — fonctionne, et c’est ce sur quoi GoodJob s’appuie. Jusqu’à 20 connexions par base peuvent être ouvertes en même temps : dimensionnez le bassin selon votre usage, soit les fils web, plus les fils de tâches, plus 3 pour l’écoute et l’entretien de GoodJob.

# config/database.yml
production:
  url: <%= ENV["DATABASE_URL"] %>
  # web threads (RAILS_MAX_THREADS) + job threads + 3 for GoodJob itself
  pool: <%= ENV.fetch("DB_POOL", 12) %>

Mémoire

Les tâches partagent la mémoire du projet avec le serveur web, et une tâche lourde partage aussi le temps de processeur, ce qui peut ralentir les requêtes pendant son exécution. Surveillez la courbe de mémoire de la vue d’ensemble après vos premières vraies tâches, et augmentez la mémoire du projet dans ses paramètres si elle approche la limite (voir forfaits et limites).

Veille, pannes et déploiements

  • Veille. Sur Démarrage, un projet sans visiteur pendant 3 heures s’endort, et ses tâches s’arrêtent avec lui. La prochaine requête le réveille, tout comme une tâche planifiée qui appelle votre app. Pour exécuter des tâches en continu, gardez le projet toujours actif, ce que Live inclut pour deux projets.
  • Pannes. Si le processus s’arrête, il est relancé après quelques secondes.
  • Déploiements. L’ancienne version dispose de 30 secondes pour terminer avant d’être arrêtée. GoodJob garde les tâches dans la base : une tâche interrompue par un déploiement est reprise par la nouvelle version; gardez les tâches plus courtes que cela, ou rendez-les sûres à exécuter deux fois.

Un processus de travail distinct

Un projet exécute un seul processus : un second processus toujours actif à côté du serveur web n’est pas encore pris en charge. Si vous avez besoin d’une mémoire isolée pour vos tâches, dites-nous ce que vous exécutez.