Description
Several scheduled jobs defined in config/schedule.yml (run via sidekiq-cron) fail at enqueue time in the Sidekiq server, so they never execute. They fire every 1–5 minutes and fail ~100% of the time, silently disabling auto-assignment, scheduled actions, agent-bot inactivity checks and pipeline task reminders. The failures are swallowed (not shown in the UI) and only visible in the Sidekiq dead set.
Affected Service
evo-ai-crm-community (Rails backend / Sidekiq)
Steps to Reproduce
- Deploy v1.0.0-rc5 with Sidekiq running the cron schedule (
Sidekiq.server?).
- Let the schedule tick (e.g.
scheduled_actions_processor_job runs * * * * *).
- Inspect
Sidekiq::DeadSet / Sidekiq::RetrySet.
Expected behavior
Scheduled ActiveJobs enqueue and run normally.
Actual behavior
Every tick lands in the dead set. Observed in production (counts over the live dead set):
ScheduledActionsProcessorJob — NameError: uninitialized constant ScheduledActionsProcessorJob and NoMethodError: undefined method 'jid=' for an instance of ScheduledActionsProcessorJob
AgentBots::InactivityCheckSchedulerJob — same pair
Pipelines::CheckOverdueTasksJob / Pipelines::TaskDueSoonReminderJob — uninitialized constant Pipelines / jid=
- downstream effects:
Inboxes::BulkAutoAssignmentJob, AutoAssignment::PeriodicAssignmentJob (auto-assignment never runs), Internal::ProcessStaleRedisKeysJob (ArgumentError: wrong number of arguments (given 1, expected 0))
Root cause (confirmed)
All affected classes inherit ApplicationJob < ActiveJob::Base (they have no jid=). They are scheduled in config/schedule.yml and loaded via Sidekiq::Cron::Job.load_from_hash in config/initializers/sidekiq.rb. No schedule entry declares active_job: true, so every cron job is stored in Redis with @active_job = false.
In Sidekiq::Cron::Job#enque! (sidekiq-cron 1.12.0):
klass_const = constantize(@klass) rescue NameError -> nil
if klass_const
is_active_job?(klass_const) ? enqueue_active_job(klass_const) : enqueue_sidekiq_worker(klass_const)
else
@active_job ? Sidekiq::Client.push(active_job_message) : Sidekiq::Client.push(sidekiq_worker_message)
end
When Sidekiq::Cron::Support.constantize(@klass) raises NameError in the Sidekiq server (its constantize does const_get(..., false) and does not trigger Zeitwerk autoload; the namespaced EvoCRM job constants — Pipelines::*, AgentBots::*, ScheduledActionsProcessorJob — are not loaded in that process), it falls back and, because @active_job is false, pushes a native Sidekiq worker message. The ActiveJob then runs through the worker path, which sets jid= on an ActiveJob instance → NoMethodError. Core Chatwoot jobs that happen to be already loaded are unaffected, which is why only a subset fails.
Suggested fix (verified in production)
Declare active_job: true on each ActiveJob entry in config/schedule.yml. This makes the fallback branch enqueue an active_job_message instead of a worker message, so it works even when constantize fails in the Sidekiq process.
We applied exactly this (via a mounted schedule.yml override) and confirmed: zero new dead-set entries for these classes over multiple ticks, and the cron jobs now enqueue and run normally.
An alternative/complementary fix is to ensure the Sidekiq server fully eager-loads the app so constantize always resolves.
Environment
- EvoCRM Community v1.0.0-rc5
- Docker Swarm
- Ruby 3.4.4
- sidekiq 7.3.1, sidekiq-cron 1.12.0
config.active_job.queue_adapter = :sidekiq, config.eager_load = true
Description
Several scheduled jobs defined in
config/schedule.yml(run via sidekiq-cron) fail at enqueue time in the Sidekiq server, so they never execute. They fire every 1–5 minutes and fail ~100% of the time, silently disabling auto-assignment, scheduled actions, agent-bot inactivity checks and pipeline task reminders. The failures are swallowed (not shown in the UI) and only visible in the Sidekiq dead set.Affected Service
evo-ai-crm-community(Rails backend / Sidekiq)Steps to Reproduce
Sidekiq.server?).scheduled_actions_processor_jobruns* * * * *).Sidekiq::DeadSet/Sidekiq::RetrySet.Expected behavior
Scheduled ActiveJobs enqueue and run normally.
Actual behavior
Every tick lands in the dead set. Observed in production (counts over the live dead set):
ScheduledActionsProcessorJob—NameError: uninitialized constant ScheduledActionsProcessorJobandNoMethodError: undefined method 'jid=' for an instance of ScheduledActionsProcessorJobAgentBots::InactivityCheckSchedulerJob— same pairPipelines::CheckOverdueTasksJob/Pipelines::TaskDueSoonReminderJob—uninitialized constant Pipelines/jid=Inboxes::BulkAutoAssignmentJob,AutoAssignment::PeriodicAssignmentJob(auto-assignment never runs),Internal::ProcessStaleRedisKeysJob(ArgumentError: wrong number of arguments (given 1, expected 0))Root cause (confirmed)
All affected classes inherit
ApplicationJob < ActiveJob::Base(they have nojid=). They are scheduled inconfig/schedule.ymland loaded viaSidekiq::Cron::Job.load_from_hashinconfig/initializers/sidekiq.rb. No schedule entry declaresactive_job: true, so every cron job is stored in Redis with@active_job = false.In
Sidekiq::Cron::Job#enque!(sidekiq-cron 1.12.0):When
Sidekiq::Cron::Support.constantize(@klass)raisesNameErrorin the Sidekiq server (itsconstantizedoesconst_get(..., false)and does not trigger Zeitwerk autoload; the namespaced EvoCRM job constants —Pipelines::*,AgentBots::*,ScheduledActionsProcessorJob— are not loaded in that process), it falls back and, because@active_jobisfalse, pushes a native Sidekiq worker message. The ActiveJob then runs through the worker path, which setsjid=on an ActiveJob instance →NoMethodError. Core Chatwoot jobs that happen to be already loaded are unaffected, which is why only a subset fails.Suggested fix (verified in production)
Declare
active_job: trueon each ActiveJob entry inconfig/schedule.yml. This makes the fallback branch enqueue anactive_job_messageinstead of a worker message, so it works even whenconstantizefails in the Sidekiq process.We applied exactly this (via a mounted
schedule.ymloverride) and confirmed: zero new dead-set entries for these classes over multiple ticks, and the cron jobs now enqueue and run normally.An alternative/complementary fix is to ensure the Sidekiq server fully eager-loads the app so
constantizealways resolves.Environment
config.active_job.queue_adapter = :sidekiq,config.eager_load = true