rails activesupport notifications - wrong db runtime value

后端 未结 3 1862
执笔经年
执笔经年 2021-02-20 08:38

I\'m trying to log requests for my REST API application. I\'m using rails notifications for this , like here http://railscasts.com/episodes/249-notifications-in-rails-3

3条回答
  •  暖寄归人
    2021-02-20 08:42

    Ok, it seems like a bug. Let see, what's going on:

    First of all, we have AR railtie for controller action and its implementation for setting db_runtime by using cleanup_view_runtime hook

    def cleanup_view_runtime
          if ActiveRecord::Base.connected?
           db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
           runtime = super
           db_rt_after_render = ActiveRecord::LogSubscriber.reset_runtime
           self.db_runtime = db_rt_before_render + db_rt_after_render
           runtime - db_rt_after_render
         else
           super
         end
    end
    

    App calls controller action -> action doing some db queries and renders some stuff -> before and after rendering AR Logger saves runtime data. Good.

    Let see how works respond_with

    def respond_with(*resources, &block)
      raise "In order to use respond_with, first you need to declare the formats your " <<
            "controller responds to in the class level" if self.class.mimes_for_respond_to.empty?
    
      if collector = retrieve_collector_from_mimes(&block)
        options = resources.size == 1 ? {} : resources.extract_options!
        options[:default_response] = collector.response
        (options.delete(:responder) || self.class.responder).call(self, resources, options)
      end
    end
    
    def self.call(*args)
      new(*args).respond
    end
    
    def to_format
      if get? || !has_errors? || response_overridden?
        default_render
      else
        display_errors
      end
    rescue ActionView::MissingTemplate => e
      api_behavior(e)
    end
    

    It seems like too much code here, but you should see the callstack for this issue: respond_with -> self.class.responder.respond -> self.class.responder.to_format -> default_render -> default_renderer raise ActionView::MissingTemplate(because we don't have any). At this moment we can see implementation for rendering :json and :xml(api_behaviour) through catching ActionView::MissingTemplate.

    Now we know how respond_with works, but AR Logger does'nt know.. cleanup_view_runtime hook is called twice: for default_renderer(at that time template data was prepared and some db queries were called, but we catch ActionView::MissingTemplate in rendering proccess)

    db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
    runtime = super # <-- here
    db_rt_after_render = ActiveRecord::LogSubscriber.reset_runtime
    

    and for api_behavour(at that time all template data was ready for rendering and no db queries)

    Some messy explanation, but I hope it will be helpful :)

提交回复
热议问题