初始化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
延迟工作小组的一张亲切的海报帮助了我: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