使用 ActiveSupport Around-Callbacks 在调用我的服务时执行代码(跟踪/日志记录)?

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

提问人:user3587051 提问时间:4/15/2022 更新时间:4/16/2022 访问量:592

问:

在我的 app/services 目录中,我有一堆服务,每个服务都有一个 initialize 方法和一个不带参数的公共方法。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

Ruby-on-Rails 回调 跟踪 ActiveSupport

评论


答:

1赞 TonyArra 4/15/2022 #1

最干净的方法是使用预置。

它看起来像这样:

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

该链接有更多详细信息。在服务中意味着将首先在模块中查找其定义。这允许在回调中包装。prependUsers::CreateService.performTraceableTraceableperform

由于我们使用的是 而不是在服务中,因此我们需要在 的块内调用 和 。prependincludedefine_callbacksset_callbackActiveSupport::Concernprepended

如果你的服务中有模块,你真的不需要或根本不需要。该模块可以是这样的,并且具有相同的结果:prependTraceablecallbacksconcernsTraceable

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

module Users
  class CreateService
    prepend Traceable
    ...
  end
end