Rails spring wisper 监听器方法缓存

Rails spring wisper listener method caching

事实证明 Spring 缓存了我的 wisper 侦听器方法(我正在编写非常简单的引擎)。

示例:

app/models/myengine/my_class.rb

class Myengine::MyClass
  include Wisper::Publisher

  def something
    # some logic
    publish(:after_something, self)
  end
end

config/initializers/wisper.rb

Wisper.subscribe(Myengine::MyObserver.new)

app/observers/myengine/my_observer.rb

class Myengine::MyObserver
  def after_something my_class_instance
    # any changes here requires Spring manual restart in order to be reflected in tests
    another_method
  end

  def another_method
    # all changes here or in any other class methods works ok with Spring and are instantly visible in tests
    return true
  end
end

Spring 重启我的意思是手动执行 spring stop 命令,这真的很烦人。

更神秘的是,我可能会将 another_method return 值更改为 false,然后测试失败,这没关系,但是当我更改 after_something 方法体时,可以说 return false 它对测试没有任何影响(比如 after_something 的主体以某种方式被缓存)。

这不是高优先级问题,因为这种奇怪的行为只在侦听器方法体内可见,并且很容易通过将所有逻辑移动到 class 中的另一个方法来克服。无论如何,它可能会令人困惑(尤其是在一开始我不知道确切问题的时候)。

这个问题是正确的,因为当你全局订阅一个监听器时,即使它的 class 被重新加载,对象仍然在内存中指向它最初构造的 class ,即使class 已同时重新加载。

config/initializers/wisper.rb 试试这个:

Rails.application.config.to_prepare do
  Wisper.clear if Rails.env.development?
  Wisper.subscribe(Myengine::MyObserver.new)
end

to_prepare 将 运行 在开发环境的每个请求之前的块,但是一次,对于生产环境来说是正常的。因此,只要您的侦听器不保持任何状态,它就会按预期工作。

在我们从重新加载的 class 中重新订阅新实例之前,需要 Wisper.clear 删除订阅的现有侦听器。请注意 #clear 将清除所有订阅者,因此如果您在多个引擎中有与上述类似的代码,则只有最后一个要加载的引擎会订阅其侦听器。