使用 ActiveSupport Around-Callbacks 在调用我的服务时执行代码 (tracing/logging)?

Use ActiveSupport Around-Callbacks to execute code (tracing/logging) around when my services are invoked?

在我的 app/services 目录中,我有一堆服务,每个服务都有一个初始化方法和一个不带参数的 public perform 方法。

显示结构的简单示例服务可能如下所示:

module Users
  class CreateService

  def initialize(name)
    @name = name
  end

  def perform
    # code to create the user
  end
end

我的目标是向我的应用程序添加跟踪,这样我就可以跟踪我的每项服务何时被调用,而无需显着修改每项服务的代码。最后,我希望做到这一点,以便在我的任何服务调用其 perform() 方法时,自动生成跟踪。

我相信这应该可以使用 ActiveSupport::Callbacks,类似于 ActiveJob 让我们为我们的工作定义 around_perform 回调的方式。我试图创建一个问题,我可以将其包含在我的服务中,以检测所需的行为

module Traceable
  extend ActiveSupport::Concern
  include ActiveSupport::Callbacks

  included do
    include ActiveSupport::Callbacks

    define_callbacks :perform

    set_callback :perform, :around, lambda { |r, block|
      puts "start the trace"
      result = block.call
      puts "end the trace"
    }
  end
end

但是,考虑到这个问题后,我想定义的回调(所有服务统一)仍然没有被调用。我怎样才能使这项工作?谢谢!

参考资料: https://api.rubyonrails.org/classes/ActiveSupport/Callbacks/ClassMethods.html https://api.rubyonrails.org/classes/ActiveSupport/Callbacks.html https://edgeapi.rubyonrails.org/classes/ActiveJob/Callbacks/ClassMethods.html#method-i-around_perform(查看around_perform class方法的源代码)

最干净的方法是使用 prepended.

看起来像这样:

module Traceable
  extend ActiveSupport::Concern

  prepended do
    include ActiveSupport::Callbacks

    define_callbacks :trace

    set_callback :trace, :around do |_r, block|
      puts "start the trace"
      block.call
      puts "end the trace"
    end
  end

  def perform
    run_callbacks :trace do
      super
    end
  end
end

module Users
  class CreateService
    prepend Traceable

    attr_accessor :name

    def initialize(name)
      @name = name
    end

    def perform
      # code to create the user
      puts "perform"
    end
  end
end

link 有更多详细信息。服务中的 prepend 表示 Users::CreateService.perform 将首先在 Traceable 模块中查找其定义。这允许 Traceableperform 包装在回调中。

由于我们在服务中使用 prepend 而不是 include,我们需要在 ActiveSupport::Concern 的内部调用 define_callbacksset_callback prepended块。

如果您 prepend 服务中的 Traceable 模块,您根本不需要 callbacksconcernsTraceable 模块可能只是这个,它会产生相同的结果:

module Traceable
  def perform
    puts "before"
    super
    puts "after"
  end
end

module Users
  class CreateService
    prepend Traceable
    ...
  end
end