Rails中多线程单例对象的策略

时间:2019-06-26 06:51:07

标签: ruby-on-rails ruby rack

我有一个引人注目的用例,其中通知在服务器级别实时发生。我想使用Rails的ActionCable通过网络套接字推送这些事件。 我如何可靠地维护一个长期存在的单例对象以响应并推送服务器级事件?

  • 我使用从/ app / lib中的文件实例化的对象创建了Rails应用的原型,该文件混合在Singleton模块中。即使使用类缓存,它也会被实例化多次,尽管打开了套接字,偶尔也会收集垃圾。

  • 将事件生成器的initialize方法标记为私有,并编写用于检查实例的Thread.main[:event_provider]的类级实例方法在开发中可以达到95%的效果,但是我担心我不这样做知道我不了解生产。偶尔我会遇到诸如“期望x_y.rb定义常数XY”之类的异常,这使我认为此方法存在问题。

  • 生产服务器最终将在需要100%正常运行时间的环境中为极少数客户提供服务。我可以选择一个有意义的服务器堆栈。

我希望了解Rack和/或ActionCable的人可以评论从服务器内部向Rails应用程序提供事件的可靠方法。

1 个答案:

答案 0 :(得分:0)

到目前为止,我正在采取的策略是在引导过程的早期实例化一个单例对象,然后使用它来维护线程。显然,为此需要线程安全实践。

文件application.rb定义了MyApp::Application。此时,我声明一个访问器my_thing_managerrequire my_thing_manager并设置self.my_thing_manager = MyThingManager.instance

class MyThingManager
    def instance
        return Thread.main[:thing_manager] unless Thread.main[:thing_manager].nil?
        Thread.main[:thing_manager] = self.new
    end

    private

    def initialize
    end
end

此方法在单个多线程进程中有效,但在群集生产环境中却不起作用。对于我的要求,这是完全可以接受的。对于多进程应用程序,可以利用钩子(例如) Puma after_worker_fork或Unicorn的after_fork来管理对Redis pubsub之类的订阅。这是即将进行的项目的要求,因此我希望进一步开发此策略。