【问题标题】:Rails singleton client lost after a Rails crashRails 崩溃后 Rails 单例客户端丢失
【发布时间】:2016-08-30 14:28:34
【问题描述】:

我有几个需要连接的第三方 API,因此我为单例行为定义了一个抽象模块,以及特定的连接器单例实例。

我的问题:每次 Rails 服务器崩溃(500 错误,本地主机),似乎我丢失了连接器的 @client 实例变量

module ServiceConnector
  extend ActiveSupport::Concern

  included do
    include Singleton
    @activated = false
    @activation_attempt = false
    @client = nil

    def client
      @client
    end

    def service_name
      self.class.name.gsub('Connector', '')
    end

    def activate
      @activation_attempt = true
      if credentials_present?
        @client = service_client
        @activated = true
      end
      status_report
    end

class MyConnector
  include ServiceConnector
  @app_id = nil
  @api_key = nil

  def credentials_present?
    @app_id.present? and @api_key.present?
  end

  def service_client
    ::MyService::Client.new(
      app_id: @app_id,
      api_key: @api_key
    )
  end

  def set_credentials(id, key)
    @app_id = id
    @api_key = key
  end

我在 Rails 初始化程序中初始化我的单例

#config/initializers/my_connectors.rb
my_service = MyConnector.instance
if my_service_should_be_activated?
  my_service.set_credentials(
    Rails.application.secrets.app_id,
    Rails.application.secrets.api_key
  )
  my_service.activate
end

def some_action_on_client
  client.push_event(...)
end

事件集

rails s
...
# MyConnector client Online and working fine
...
# error 500 on some controller
# (next client request)
# MyConnector @client variable mysteriously set to nil

【问题讨论】:

  • 您是否尝试过使用Rails.logger 来查看它是否被正确初始化?崩溃与进程重启没有什么不同。应该重新初始化单例。
  • 每次重新加载应用后都会发生这种情况吗?当 Rails 重新加载应用程序代码时,它不会重新执行初始化程序。发生的情况是您的类已定义,它们包含关注点,然后将@client 设置为 nil。但是,初始化程序没有运行,所以@client 永远不会再次分配。我怀疑每次代码更改后都会发生这种情况,而您只是在触发错误后才注意到它。
  • 啊,感谢您为我指明了正确的方向,这很可能是发生的事情。那你会怎么处理呢?我将使用不同的单例模式变体发布解决方案,但我会很好奇/接受解释我应该如何编写在这些情况下正确重新加载的服务的答案。

标签: ruby-on-rails ruby singleton ruby-on-rails-5 activesupport


【解决方案1】:

我最终使用 there 所述的模块单例模式重写了代码

基本上,它只包含使用一个模块和模块类变量

module ServiceConnector
  extend ActiveSupport::Concern

  class ConnectorError < Exception
  end

  class ActivationError < ConnectorError
  end

  included do
    @@activated = false
    @@activation_attempt = false
    @@client = nil

    # all other methods as class methods with self.

class MyConnector
  include ServiceConnector

  @@some_credential = nil

  def self.set_credentials(cred)
    @@some_credential = cred
  end

  def self.credentials_present?
    @@some_credential != nil
  end

  def self.service_client
    ::MyService.new(
      @@some_credential,
    )
  end

  # also all other methods with self.

然后使用MyConnector.some_method 直接访问,而不是先调用.instance

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-25
    • 2022-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多