ActiveSupport ::通知とは何ですか、なぜ必要なのですか?

ActiveSupport::Notifications



は、レールベースの通知システムです。 Railsで特定の通知をサブスクライブし、送信時にコードを呼び出すことができます。 これはActiveSupport::Callbacks



多少似ていますが、プロジェクト全体で機能し、イベントを事前に通知する必要はありません。







たとえば、通知'render'



サブスクライブでき'render'







 ActiveSupport::Notifications.subscribe("render") do |*args| #        render end
      
      







正規表現を通知の名前として使用し、その表現に一致するすべての通知をサブスクライブできます。 すべての通知をサブスクライブする場合は、 subscribe



メソッドに何も渡さないでください。 subscribe



メソッドは、サブスクライバーへのリンクを返します;通知のサブスクリプションを解除する必要がある場合があります。



ActiveSupport::Notifications.publish



メソッドを使用して通知を送信できます。



 ActiveSupport::Notifications.publish('render', 'arg1', 'arg2')
      
      







subscribe



ブロックでは、 'render'



'arg1'



、および'arg2'



が渡されます。



これらの機能を直接使用するRailsのコードは見つかりませんでした。おそらく、この機能はフレームワークのユーザーがアプリケーションタスクに使用するはずです。 しかし、 ActiveSupport::Notifications



には非常に便利なinstrument



メソッドがあります。 ブロックを受信すると、ブロック実行の開始と終了のタイムスタンプと、追加データを含むハッシュを含む通知を送信します。 Railsはこのメカニズムを使用し、間接的に、 subscribe



およびpublish



メソッドを使用して開発環境で詳細なログを作成します(本番環境では同じ「メーター」が使用されますが、すべてがログに書き込まれるわけではありません)



同じ目的で、これらの「メーター」をアプリケーションで使用できます。 このメソッドでチェックインするコードをラップし、実行結果をログに書き込むことができます。 たとえば、追跡したい実行速度のメソッドがあります。



 def do_something #    end
      
      







ActiveSupport::Notifications.instrument



ブロックでラップするだけです



 def do_something ActiveSupport::Notifications.instrument('benchmark.do_something', desc: 'Some description') do #    end end
      
      







config/initializers/benchmarking.rb



などの場所では、 'benchmark.'



という行ですべての通知config/initializers/benchmarking.rb



サブスクライブし'benchmark.'







 logger = Logger.new(File.join(Rails.root, 'log', "benchmarks.log")) ActiveSupport::Notifications.subscribe(%r/benchmark\.*/) do |name, start, ending, transaction_id, payload| method = name.split(?.).last duration = (1000.0 * (ending - start)) message = if payload[:exception].present? payload[:exception].join(' ') else payload[:desc].to_s end logger.info("Benchmark:%s: %.0fms - %s" % method, duration, message) end
      
      







次の変数がブロックに転送されます: name, start, ending, transaction_id, payload











次に、実行時間をログに書き込みます。 例外が発生した場合、 payload[:exception]



は、例外の名前とエラーメッセージを含む配列を記録します。 これも考慮に入れる必要があります。



ActiveSupport::Notifications



RailsロギングのActiveSupport::Notifications



役割の詳細については、 ActiveSupport::LogSubscriber



ActiveRecord::LogSubscriber



ActionController::LogSubscriber



およびActionMailer::LogSubscriber







一時的に通知をサブスクライブする別のメソッドがありますが、それに渡されたブロックが実行されている間のみです。



 callback = lambda do|*args| #        #  "event.name" end ActiveSupport::Notifications.subscribed(callback, "event.name") do #        end
      
      







イベントのサブスクリプunsubscribe



するには、 unsubscribe



メソッドを呼び出して、サブスクライバーリンクを渡します。



 ActiveSupport::Notifications.unsubscribe(subscriber)
      
      







通知配信メカニズム自体は、 ActiveSupport::Notifications::Fanout



に隠されていますActiveSupport::Notifications::Instrumenter



クラスを見ると興味深いでしょう。このクラスは、 instrument



メソッドでブロックの実行時間を測定する役割を果たします。



例として、 ActiveSupport::Notifications



を使用してメソッドの実行時間をリアルタイムで計算するためのActiveSupport::Notifications







 class Module def benchmark_it *names options, names = benchmark_options_and_names(*names) names.each do |name| target, punctuation = name.to_s.sub(/([?!=])$/, ''), $1 define_method "#{target}_with_benchmark#{punctuation}" do |*args| ActiveSupport::Notifications.instrument("benchmark.#{self.name}.#{name}", options) do send("#{target}_without_benchmark#{punctuation}", *args) end end alias_method_chain name, :benchmark end end protected def benchmark_options_and_names *args options = args.last.is_a?(Hash) ? args.pop : {} [{desc: ''}.merge(options), args] end end ActiveSupport::Notifications.subscribe(%r/benchmark\.*/) do |name, start, ending, transaction_id, payload| _, classname, method = name.split(?.) duration = (1000.0 * (ending - start)) message = if payload[:exception].present? payload[:exception].join(' ') else payload[:desc].to_s end Rails.logger.info("Benchmark: %s.%s: %.0fms - %s" % classname, method, duration, message) end
      
      







このように使用します:



 class MyClass def my_method #   - end #       benchmark_it :my_method, desc: '  ' end
      
      







これは何のためですか? 同じRailsの例を使用すると、コードが異なる疎結合コンポーネントで構成されている場合、そのような通知を使用してそれらとの対話を確立できることがわかります。 したがって、ORMまたは他のライブラリ( MyORM



など)をMyORM



して、 MyORM::LogSubscriber



から継承したMyORM::LogSubscriber



クラスにロギングタスクをActiveSupport::LogSubscriber



ます。 ログの表示を担当するメッセージコードはアプリケーションによって塗りつぶされませんが、1か所にあります。 もちろん、ライブラリ全体にセンサーを配置する必要があります。 ちなみに、これらの同じセンサーは、ロギング以外のあらゆるものに使用できます。



一方で、私のコードはRailsに結び付けられておらず、一方で、Railsはライブラリについても何も知りませんが、それにもかかわらず、私のgemは共通のロギングシステムに接続されています。



当然、ロギングは通知のアプリケーションの唯一の領域ではありませんが、この例では通知が必要な理由を簡単に示すことができます。



All Articles