【问题标题】:Strategies for multithreaded singleton object in RailsRails 中多线程单例对象的策略
【发布时间】:2019-06-26 06:51:07
【问题描述】:

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

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

  • 将事件生产者的 initialize 方法标记为私有并编写一个检查 Thread.main[:event_provider] 实例的类级实例方法在开发中工作 95%,但我担心我不知道我不知道的事情不知道生产。偶尔我会遇到“Expected x_y.rb to define constant XY”之类的异常,这让我觉得这种方法有问题。

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

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

【问题讨论】:

  • 旁注: “Expected x_y.rb to define constant XY” 消息与可靠性无关,这是 Rails 的“智能”自动加载抱怨您的文件命名/路径。
  • 旁注 #2:“可靠地维护一个长期存在的单例对象来处理服务器级事件”如果从不使用 Rails 则很少见解决方案。通用方法是使用消息队列之类的东西(从 Rails 那里发送事件),并拥有一个可靠的应用程序(可靠的首先排除 Rails),它读取队列,向消费者发送事件和 然后确认消息。这样可以保证每条消息都得到处理。
  • 您是否考虑过使用 iodine 对 pub/sub 的内置支持?您可以通过向订阅添加代码块(因此订阅调用块而不是发送数据)将其与 ActionCable 一起使用(虽然不如直接发布/订阅到原始 WebSockets 推荐)...(PS,我有偏见)
  • @AlekseiMatiushkin 我们正在考虑的一种方法是在本地连接到 Rails 应用程序的子进程,可能作为 websocket 客户端。我在这里的部分动机是更多地了解 ActionCable 如何在 Rails 中长期存在,以及第三方是否有可能(或可取)实现同样的目标。
  • @Myst 现在看看。谢谢!

标签: ruby-on-rails ruby rack


【解决方案1】:

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

文件 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 之类的订阅。这将是即将到来的项目的要求,因此我希望进一步制定此策略。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-02
    • 2023-03-14
    相关资源
    最近更新 更多