Jobs en arrière-plan Rails en 2026 : Sidekiq vs Good Job et questions d'entretien
Comparaison approfondie entre Sidekiq, Good Job et Solid Queue pour les tâches asynchrones Rails, avec les questions techniques posées en entretien.

Les jobs en arrière-plan Rails ont considérablement évolué avec Rails 8.x et l'introduction de Solid Queue comme backend Active Job par défaut. Le choix entre Sidekiq, Good Job et Solid Queue dépend des exigences de débit, des contraintes d'infrastructure et des fonctionnalités nécessaires à chaque projet.
Pour les nouveaux projets Rails 8, Solid Queue constitue le point de départ recommandé. Sidekiq s'impose pour les charges de travail à haut débit dépassant 100 000 jobs par jour ou lorsque la latence au niveau Redis est critique. Good Job convient aux jobs stockés dans PostgreSQL avec support natif des batches et des contraintes d'unicité.
Comment Active Job unifie le traitement en arrière-plan
Active Job fournit une interface standardisée pour déclarer, mettre en file d'attente et exécuter des tâches en arrière-plan dans Rails. Ce framework abstrait les différences entre les backends de file d'attente, permettant au code de rester portable entre Sidekiq, Good Job, Solid Queue ou tout autre adaptateur.
# app/jobs/payment_processor_job.rb
class PaymentProcessorJob < ApplicationJob
queue_as :critical
retry_on Stripe::RateLimitError, wait: :polynomially_longer, attempts: 5
discard_on Stripe::InvalidRequestError
def perform(order_id)
order = Order.find(order_id)
PaymentService.process(order)
OrderMailer.confirmation(order).deliver_later
end
endLes callbacks retry_on et discard_on gèrent les échecs transitoires et les erreurs permanentes sans code spécifique au backend. La directive queue_as attribue une priorité que chaque backend interprète selon sa propre stratégie de traitement des files d'attente.
Sidekiq 8.x : débit optimisé avec Redis
Sidekiq reste la référence en matière de performance pour les jobs en arrière-plan Rails. La série 8.x requiert Ruby 3.2+, Rails 7.0+ et Redis 7.2+ (Valkey et Dragonfly fonctionnent comme remplacements directs depuis le changement de licence Redis).
# config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
config.redis = { url: ENV.fetch('REDIS_URL') }
config.concurrency = 10
end
Sidekiq.configure_client do |config|
config.redis = { url: ENV.fetch('REDIS_URL') }
endSidekiq 8 a introduit trois changements majeurs : une interface Web entièrement réécrite réduisant le CSS de 160 Ko à 16 Ko et le temps de rendu moyen de 55 ms à 3 ms, le profilage des jobs avec Vernier accessible via un nouvel onglet Profiles, et la conservation des métriques jusqu'à 72 heures.
Quand choisir Sidekiq
Sidekiq convient aux charges de travail nécessitant un débit soutenu, une latence de récupération des jobs inférieure à la milliseconde, ou des fonctionnalités entreprise comme la limitation de débit et les jobs uniques justifiant l'utilisation de Redis. Les Capsules, introduites en version 7.0 et désormais standard, permettent à un processus Sidekiq d'exécuter plusieurs pools de threads isolés avec leur propre concurrence et leurs propres files d'attente.
# config/sidekiq.yml
:concurrency: 10
:queues:
- [critical, 3]
- [default, 2]
- [low, 1]
# Capsules pour traitement isolé
:capsules:
imports:
:concurrency: 2
:queues:
- importsL'API d'embedding permet également d'exécuter Sidekiq à l'intérieur du processus Puma pour les petites applications, de manière similaire au plugin Puma de Solid Queue.
Prêt à réussir tes entretiens Ruby on Rails ?
Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.
Good Job 4.x : batches et unicité natives PostgreSQL
Good Job utilise LISTEN/NOTIFY de PostgreSQL pour la récupération des jobs et les verrous consultatifs pour garantir une exécution unique. La version 4.19.x (actuelle en septembre 2026) supporte Rails 6.1+ et Ruby 3.0+.
# config/application.rb
config.active_job.queue_adapter = :good_job
# config/initializers/good_job.rb
Rails.application.configure do
config.good_job.execution_mode = :async
config.good_job.max_threads = 5
config.good_job.poll_interval = 5
config.good_job.shutdown_timeout = 25
endGood Job inclut les batches et les jobs uniques dans la version open-source, des fonctionnalités que Sidekiq réserve aux licences payantes. L'appel perform_later insère une ligne dans la table good_jobs au sein de la même transaction de base de données que le code appelant, donc si la transaction est annulée, le job n'est jamais créé.
Batches sans licence
# app/jobs/batch_import_job.rb
class BatchImportJob < ApplicationJob
def perform(batch, params)
batch.on(:finish, ImportCompletionJob, params)
params[:file_ids].each do |file_id|
batch.add do
ProcessFileJob.perform_later(file_id)
end
end
end
end
# Mise en file d'attente du batch
GoodJob::Batch.enqueue do |batch|
BatchImportJob.perform_later(batch, file_ids: [1, 2, 3])
endJobs uniques pour l'idempotence
# app/jobs/sync_inventory_job.rb
class SyncInventoryJob < ApplicationJob
include GoodJob::ActiveJobExtensions::UniqueJob
good_job_control_concurrency_with(
perform_limit: 1,
key: -> { "sync_inventory_#{arguments.first}" },
duration: 1.hour
)
def perform(warehouse_id)
InventorySync.run(warehouse_id)
end
endLa contrainte perform_limit: 1 garantit qu'une seule synchronisation s'exécute par entrepôt à tout moment, évitant le travail en double lorsque le même job est mis en file d'attente plusieurs fois.
Solid Queue : le défaut de Rails 8
Solid Queue stocke les jobs dans la base de données de l'application en utilisant FOR UPDATE SKIP LOCKED, une fonctionnalité PostgreSQL et MySQL qui transforme une table ordinaire en file d'attente de jobs. Les nouvelles applications Rails 8 sont livrées avec Solid Queue configuré par défaut.
# config/solid_queue.yml
production:
dispatchers:
- polling_interval: 1
batch_size: 500
workers:
- queues: "*"
threads: 5
polling_interval: 0.1Solid Queue peut s'exécuter à l'intérieur du processus du serveur web Puma avec SOLID_QUEUE_IN_PUMA=true, ce qui simplifie le déploiement pour les applications qui n'ont pas besoin de processus worker dédiés. Les jobs persistent dans les tables de la base de données, survivant aux redémarrages de processus et aux déploiements sans dépendances externes.
Tableau comparatif des fonctionnalités
| Fonctionnalité | Sidekiq 8.x | Good Job 4.x | Solid Queue 1.x |
|---|---|---|---|
| Backend | Redis 7.2+ | PostgreSQL | PostgreSQL/MySQL/SQLite |
| Batches | Pro/Enterprise | Inclus | Prévu |
| Jobs uniques | Enterprise | Inclus | Manuel via verrous |
| Planification cron | Enterprise | Inclus | Via solid_queue_cron |
| Interface Web | Incluse | Incluse | Minimale (Mission Control) |
| Plafond de débit | 100k+ jobs/min | 10k jobs/min | 10k jobs/min |
| Intégration Puma | Oui (8.x) | Non | Oui |
| Licence | LGPL + Commercial | MIT | MIT |
Questions d'entretien sur les jobs en arrière-plan Rails
Les entretiens techniques sondent fréquemment la compréhension de la fiabilité des jobs, des stratégies de retry et des décisions architecturales. Voici des questions qui distinguent les candidats expérimentés.
Q1 : Quelle différence entre retry_on et la logique de retry spécifique au backend ?
retry_on est un callback Active Job qui fonctionne avec tous les backends. Il intercepte des exceptions spécifiques, applique une stratégie d'attente (:polynomially_longer effectue un backoff exponentiel) et remet le job en file d'attente. La logique de retry spécifique au backend, comme sidekiq_retry_in de Sidekiq, ne fonctionne qu'avec ce backend et peut surcharger le comportement d'Active Job.
# Retry Active Job (portable)
class ApiSyncJob < ApplicationJob
retry_on Net::OpenTimeout, wait: :polynomially_longer, attempts: 8
def perform(record_id)
ExternalApi.sync(record_id)
end
endQ2 : Que devient un job si la transaction de base de données qui l'a mis en file d'attente est annulée ?
Avec les files d'attente basées sur la base de données (Good Job, Solid Queue), la ligne du job fait partie de la transaction, donc elle est annulée avec tout le reste. Avec les files d'attente basées sur Redis (Sidekiq), le job est déjà dans Redis avant la fin de la transaction, créant des jobs orphelins. La solution est d'utiliser les callbacks after_commit :
# Pattern correct pour Sidekiq
class Order < ApplicationRecord
after_commit :enqueue_confirmation, on: :create
private
def enqueue_confirmation
OrderConfirmationJob.perform_later(id)
end
endQ3 : Quand Good Job surpasserait-il Sidekiq ?
Good Job surpasse Sidekiq lorsque le coût opérationnel de Redis dépasse ses avantages en termes de débit. Pour les applications traitant moins de 50 000 jobs par jour, les files d'attente basées sur PostgreSQL évitent la complexité d'infrastructure, de monitoring et de basculement d'un cluster Redis séparé. Good Job fournit également les batches et les jobs uniques sans frais de licence, ce qui compte pour les équipes ayant besoin de ces fonctionnalités avec un budget limité.
Q4 : Expliquer l'idempotence des jobs et son importance pour les retries
L'idempotence signifie que l'exécution du même job plusieurs fois produit le même résultat qu'une seule exécution. Les jobs doivent être idempotents car les pannes réseau, les crashs de processus ou la gestion des timeouts peuvent causer des exécutions en double. Les techniques incluent les contraintes d'unicité dans la base de données, la vérification des résultats existants avant traitement et l'utilisation de clés d'idempotence externes pour les APIs de paiement.
# Traitement de paiement idempotent
def perform(order_id, idempotency_key)
return if Payment.exists?(idempotency_key: idempotency_key)
Payment.create!(
order_id: order_id,
idempotency_key: idempotency_key,
amount: Order.find(order_id).total
)
endQ5 : Comment gérer les jobs qui doivent s'exécuter exactement une fois sur des workers distribués ?
Les verrous distribués empêchent l'exécution concurrente. Good Job utilise les verrous consultatifs PostgreSQL. Sidekiq Enterprise propose les jobs uniques. Pour une implémentation manuelle, utiliser Redis SETNX ou PostgreSQL pg_try_advisory_lock :
class ExclusiveJob < ApplicationJob
def perform(resource_id)
lock_key = "exclusive_job:#{resource_id}"
ActiveRecord::Base.connection.execute(
"SELECT pg_try_advisory_lock(hashtext('#{lock_key}'))"
).first['pg_try_advisory_lock'] or return
begin
process_resource(resource_id)
ensure
ActiveRecord::Base.connection.execute(
"SELECT pg_advisory_unlock(hashtext('#{lock_key}'))"
)
end
end
endPasse à la pratique !
Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.
Choisir le bon backend pour les jobs en arrière-plan Rails
- Commencer avec Solid Queue pour les nouveaux projets Rails 8 qui n'ont pas encore Redis dans leur stack
- Passer à Sidekiq quand le volume de jobs dépasse 50 000 par jour ou que la latence de récupération inférieure à 100 ms compte
- Choisir Good Job pour les déploiements PostgreSQL uniquement nécessitant batches, jobs uniques ou planification cron sans coûts de licence
- Utiliser les callbacks
after_commitlors de la mise en file d'attente de jobs avec Sidekiq pour éviter les jobs orphelins en cas d'annulation de transaction - Rendre chaque job idempotent car les retries et le traitement distribué peuvent causer des exécutions en double
- Pour les entretiens, démontrer la compréhension de la mise en file d'attente transactionnelle des jobs, des stratégies de retry et des patterns de verrouillage distribué
Tu saurais repérer le bug en Ruby on Rails ?
Un vrai bout de code, un bug caché, une tentative par jour. Sans compte pour essayer.

Écrit par
Anthony Fillion-MailletFondateur de SharpSkill
Développeur fullstack depuis plus de 10 ans. Il dirige SharpSkill et répond de tout ce qui y est publié.
Mis à jour le 12 septembre 2026
Tags
Partager
Articles similaires

Service Objects Rails en 2026 : Design Patterns, PORO et Questions d'Entretien Technique
Les service objects Rails permettent d'extraire la logique métier des contrôleurs et modèles vers des classes Ruby simples. Ce guide couvre les patterns de conception, les implémentations PORO et les questions d'entretien technique les plus courantes.

API GraphQL avec Rails en 2026 : graphql-ruby, Subscriptions et Questions d'Entretien
Construire une API GraphQL prête pour la production avec Rails 8 et graphql-ruby. Conception de schéma, mutations, subscriptions avec ActionCable et préparation aux entretiens.

Rails Active Storage en 2026 : Upload de fichiers, intégration S3 et questions d'entretien
Guide complet sur Rails Active Storage en 2026 : configuration des uploads de fichiers, intégration AWS S3, variantes d'images et questions techniques pour préparer les entretiens Ruby on Rails.