Rails初始化程序未配置DelayedJob Worker

时间:2019-02-21 14:01:49

标签: ruby-on-rails delayed-job

初始化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

1 个答案:

答案 0 :(得分:0)

“延迟工作”小组的一位好心的海报帮助我: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