Skip to content

[Bug]: sidekiq-cron scheduled ActiveJobs fail at enqueue (uninitialized constant / undefined method "jid=") — auto-assignment & scheduled actions silently dead #117

@firstplaceservdig1

Description

@firstplaceservdig1

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

  1. Deploy v1.0.0-rc5 with Sidekiq running the cron schedule (Sidekiq.server?).
  2. Let the schedule tick (e.g. scheduled_actions_processor_job runs * * * * *).
  3. 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):

  • ScheduledActionsProcessorJobNameError: uninitialized constant ScheduledActionsProcessorJob and NoMethodError: undefined method 'jid=' for an instance of ScheduledActionsProcessorJob
  • AgentBots::InactivityCheckSchedulerJob — same pair
  • Pipelines::CheckOverdueTasksJob / Pipelines::TaskDueSoonReminderJobuninitialized 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions