From b0e7688aadf55c1d9d8353c6201545df6d95704b Mon Sep 17 00:00:00 2001 From: gabrieljablonski Date: Fri, 17 Apr 2026 21:24:29 -0300 Subject: [PATCH] fix(jobs): resolve channel service class by name in SendReplyJob CHANNEL_SERVICES held frozen references to service class objects, captured when SendReplyJob was first autoloaded. In test env (cache_classes=false), Zeitwerk reloads triggered between specs (notably by request specs) replaced the constants with new class objects, leaving the hash pointing to the stale ones. RSpec stubs applied to the current constant were then bypassed when the job called service_class.new(...) through the stale reference, causing flaky CI failures in spec/jobs/send_reply_job_spec.rb when sharded together with V2::ReportBuilder + Captain::Preferences specs. Storing class names as strings and resolving via constantize per call fixes this and is the standard Rails autoload-safe pattern. --- app/jobs/send_reply_job.rb | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/jobs/send_reply_job.rb b/app/jobs/send_reply_job.rb index e892c189a..eec722e8d 100644 --- a/app/jobs/send_reply_job.rb +++ b/app/jobs/send_reply_job.rb @@ -2,17 +2,17 @@ class SendReplyJob < ApplicationJob queue_as :high CHANNEL_SERVICES = { - 'Channel::TwitterProfile' => ::Twitter::SendOnTwitterService, - 'Channel::TwilioSms' => ::Twilio::SendOnTwilioService, - 'Channel::Line' => ::Line::SendOnLineService, - 'Channel::Telegram' => ::Telegram::SendOnTelegramService, - 'Channel::Whatsapp' => ::Whatsapp::SendOnWhatsappService, - 'Channel::Sms' => ::Sms::SendOnSmsService, - 'Channel::Instagram' => ::Instagram::SendOnInstagramService, - 'Channel::Tiktok' => ::Tiktok::SendOnTiktokService, - 'Channel::Email' => ::Email::SendOnEmailService, - 'Channel::WebWidget' => ::Messages::SendEmailNotificationService, - 'Channel::Api' => ::Messages::SendEmailNotificationService + 'Channel::TwitterProfile' => '::Twitter::SendOnTwitterService', + 'Channel::TwilioSms' => '::Twilio::SendOnTwilioService', + 'Channel::Line' => '::Line::SendOnLineService', + 'Channel::Telegram' => '::Telegram::SendOnTelegramService', + 'Channel::Whatsapp' => '::Whatsapp::SendOnWhatsappService', + 'Channel::Sms' => '::Sms::SendOnSmsService', + 'Channel::Instagram' => '::Instagram::SendOnInstagramService', + 'Channel::Tiktok' => '::Tiktok::SendOnTiktokService', + 'Channel::Email' => '::Email::SendOnEmailService', + 'Channel::WebWidget' => '::Messages::SendEmailNotificationService', + 'Channel::Api' => '::Messages::SendEmailNotificationService' }.freeze def perform(message_id) @@ -21,10 +21,10 @@ class SendReplyJob < ApplicationJob return send_on_facebook_page(message) if channel_name == 'Channel::FacebookPage' - service_class = CHANNEL_SERVICES[channel_name] - return unless service_class + service_class_name = CHANNEL_SERVICES[channel_name] + return unless service_class_name - service_class.new(message: message).perform + service_class_name.constantize.new(message: message).perform end private