【问题标题】:DelayedJob Worker not configured by rails initializersRails 初始化程序未配置 DelayedJob Worker
【发布时间】:2025-12-30 10:55:06
【问题描述】:

什么是初始化 Rails 应用程序状态的正确方法,以便 DelayedJob 工作人员(以及 rails 应用程序)受到该初始化的影响?我在应用程序配置设置时遇到问题在我的 Rails 初始化程序中,我的 DelayedJob 作业似乎看不到。

我在 Rails 初始化程序中编排了几个“服务”可观察/单例(这是一个人为的示例):

# my_app_initializer.rb
puts 'initializing my app...' # this DOES get logged in DJ worker

ShopActivityService.instance.add_observer(NotificationService.instance, func=:handle_shop_activity)

# if someone calls ShopActivityService.do_activity(), notification service sends an email

这个想法是,只要有一些“商店活动”,“通知服务”就会发送一封电子邮件或其他东西。

问题是,如果延迟的作业工作者调用ShopActivityService,NotificationService 似乎没有注册为观察者,因此它不会收到通知。

我注意到当我使用rails jobs:work 启动应用程序时会调用初始化程序,但是作业本身中的代码必须从其他环境或上下文中运行?

编辑:更简单的方式来演示问题:

# my_job.rb
class MyJob
  @@x = 0
  def self.inc_x
    @@x = @@x + 1
  end
  def self.print_x
    puts "x is #{@@x}"
  end

  def self.schedule_job
    new.delay.execute_job
  end

  def execute_job
    self.class.print_x
  end
end

# my_job_initializer.rb
MyJob.inc_x

然后在rails console 中会出现意想不到的结果:

MyJob.print_x
# prints 'x is 1' as expected

MyJob.schedule_job
# the delayed job worker process prints 'x is 0'

编辑 2:我在 DJ group 上提出了这个问题,并创建了一个小型 github 项目来演示该问题:https://github.com/cechner/dj_test

【问题讨论】:

    标签: ruby-on-rails delayed-job


    【解决方案1】:

    Delayed Job 小组的一张好心的海报帮助了我:https://groups.google.com/forum/#!topic/delayed_job/hgZvJtydLWs

    总而言之,默认情况下,开发模式下的 Rails 会对 app/ 目录中运行的所有代码进行“代码重新加载”。但是,它不会重新加载 config/initializers/ 目录中的代码。所以我的服务正在重新加载(因此观察者被清除),但协调这些服务的初始化(通过注册观察者)没有重新运行。

    我知道使用单例共享全局状态的问题,但我不确定在运行时编排服务的“正确”或社区认可的方法是什么。

    目前我已经解决了以下问题:

    # config/initializers/my_application_config.rb
    module MyApplication
      class Application < Rails::Application
        # was previously doing config.after_initialize, but to_prepare seems to be called every time a reload happens
        config.to_prepare do
          ServiceOrchestrator.prepare
        end
      end
    end
    
    # app/services/service_orchestrator.rb
    class ServiceOrchestrator
      def self.prepare
        # clear because this seems to be invoked twice every reload for some reason
        ShopActivityService.instance.delete_observers
    
        ShopActivityService.instance.add_observer(NotificationService.instance, func=:handle_shop_activity)
      end
    end
    

    【讨论】: