уведомления rails activesupport - неправильное значение времени выполнения db

Я пытаюсь регистрировать запросы для своего приложения REST API. Я использую для этого уведомления rails, например здесь http://railscasts.com/episodes/249-notifications-in-rails-3

Я не могу понять, как решить одну проблему с уведомлениями о рельсах.

мой код инициализатора

ActiveSupport::Notifications.subscribe "process_action.action_controller" do |name, start, finish, id, payload|
 p name
 p start 
 p finish
 p id
 p payload
end



Controller respond section

    class PostsController < ApplicationController
      # GET /posts
      # GET /posts.json

      respond_to  :json, :html
     ....
end

Действие создания контроллера

  def create
    @post = Post.new(params[:post])
    @post.save!
    respond_with(@post, :location => nil)
 end

Консольный вывод

"process_action.action_controller"
2013-02-02 20:13:11 +0200
2013-02-02 20:13:11 +0200
"951b8999e9b71d4a8949"
{:controller=>"PostsController", :action=>"create", :params=>{"utf8"=>"✓", "authenticity_token"=>"1WugY9gh6ZCRXjfBTuckye3c9XDvtCqMQ2JdBpCo88s=", "post"=>{"name"=>"post3", "title"=>"post3", "content"=>"post3"}, "commit"=>"Create Post", "action"=>"create", "controller"=>"posts"}, :format=>:html, :method=>"POST", :path=>"/posts", :status=>302, :view_runtime=>nil, :db_runtime=>0}

Как видите, :db_runtime=>0

Однако, если я изменю код действия контроллера на шаблон по умолчанию

  def create
    @post = Post.new(params[:post])
    #@post.save!
    #respond_with(@post)
    respond_to do |format|
      if @post.save
        format.html { redirect_to @post, notice: 'Post was successfully created.' }
        format.json { render json: @post, status: :created, location: @post }
      else
        format.html { render action: "new" }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

Я вижу

"process_action.action_controller"
2013-02-02 20:22:51 +0200
2013-02-02 20:22:51 +0200
"bf2a3173c08a0fd9008e"
{:controller=>"PostsController", :action=>"create", :params=>{"utf8"=>"✓", "authenticity_token"=>"1WugY9gh6ZCRXjfBTuckye3c9XDvtCqMQ2JdBpCo88s=", "post"=>{"name"=>"post3", "title"=>"post3", "content"=>"post3"}, "commit"=>"Create Post", "action"=>"create", "controller"=>"posts"}, :format=>:html, :method=>"POST", :path=>"/posts", :status=>302, :view_runtime=>nil, :db_runtime=>4.727}

:db_runtime=>4,727

В чем причина этого и как я могу это исправить, чтобы он работал в первом примере? Спасибо !

УПД

 bundle show rails
/Users/admin/.rvm/gems/ruby-1.9.3-p125/gems/rails-3.2.11
rvm current
ruby-1.9.3-p125

UPD2

Кажется, что это не работает, когда я использую response_with! Может кто-нибудь сказать мне, почему? Спасибо


person Fivell    schedule 02.02.2013    source источник
comment
привет Fivell, только что я попытался создать то же самое. вот что я получаю при использовании response_with: Notification: process_action.action_controller 2013-02-06 13:59:21 +0600 2013-02-06 13:59:21 +0600 f2da3803410cccda546a {:controller=›PostsController, :action= ›show, :params=›{action=›show, controller=›posts, id=›12}, :format=›:html, :method=›GET, :path=›/posts/12, :status=› 200, :view_runtime=>9,479712, :db_runtime=>0,267212}   -  person Said Kaldybaev    schedule 06.02.2013
comment
rails 3.2.11, ruby ​​1.9.3p194 (20 апреля 2012 г., редакция 35410) [x86_64-linux]   -  person Said Kaldybaev    schedule 06.02.2013
comment
привет, сказал, что это работает с GET, но не с POST   -  person Fivell    schedule 06.02.2013
comment
Привет, вот мой почтовый запрос: Уведомление: process_action.action_controller 07-02-2013 12:44:53 +0600 07-02-2013 12:44:53 +0600 6b876f07776723b5ac92 {:controller=›PostsController, :action=›create, :params=›{utf8=›✓, authentication_token=›V/Y4apQ4S4Qxb0A9hmZvNX6C1jCQQ469YTNezlOpsq0=, post=›{title=›asd, content=›asd}, commit=›Create Post, action=›create, controller=›posts}, :format=›:html, :method=›POST, :path=›/posts, :status=›406, :view_runtime=›nil, :db_runtime=›353.078918   -  person Said Kaldybaev    schedule 07.02.2013
comment
@SaidKaldybaev, вы можете сделать так, чтобы ваш почтовый запрос возвращал статус 200 вместо 406? попробуйте добавить response_to :json, :html в код вашего контроллера   -  person Fivell    schedule 07.02.2013
comment
и удалите :location =› nil из метода response_with   -  person Fivell    schedule 07.02.2013
comment
аааа, тогда я вижу, получить 0, это действительно странно.   -  person Said Kaldybaev    schedule 07.02.2013
comment
хорошо) тогда я не сумасшедший!!!!   -  person Fivell    schedule 07.02.2013
comment
@SaidKaldybaev, я думаю, это ошибка в рельсах!   -  person Fivell    schedule 07.02.2013
comment
ааа, ты не сумасшедший, ты пытался создать проблему в github?   -  person Said Kaldybaev    schedule 07.02.2013
comment
еще нет, я сейчас отлаживаю, чтобы найти глючное место   -  person Fivell    schedule 07.02.2013


Ответы (3)


Хорошо, похоже на ошибку. Давайте посмотрим, что происходит:

Во-первых, у нас есть AR railtie для действия контроллера и его реализация для установки db_runtime с помощью хука cleanup_view_runtime.

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

Приложение вызывает действие контроллера -> действие, выполняющее некоторые запросы к базе данных и отображающее некоторые вещи -> до и после рендеринга AR Logger сохраняет данные времени выполнения. Хорошо.

Давайте посмотрим, как работает response_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

Кажется, здесь слишком много кода, но вы должны увидеть стек вызовов для этой проблемы: response_with -> self.class.responder.respond -> self.class.responder.to_format -> default_render -> default_renderer у нас нет). На данный момент мы можем видеть реализацию для рендеринга :json и :xml(api_behaviour) через перехват ActionView::MissingTemplate.

Теперь мы знаем, как работает response_with, но AR Logger не знает.. Хук cleanup_view_runtime вызывается дважды: для default_renderer (в это время данные шаблона были подготовлены и были вызваны некоторые запросы к БД, но мы ловим ActionView::MissingTemplate в процессе рендеринга)

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

и для api_behavour(на тот момент все данные шаблона были готовы к рендерингу и никаких запросов к БД)

Немного сумбурное объяснение, но надеюсь будет полезно :)

person Dmitry Dedov    schedule 07.02.2013
comment
Да, Дмитрий, отладчик помог мне найти сегодня, вы видели проблему с решением, которое я сделал около часа назад github.com/rails/rails/issues/9215 - person Fivell; 08.02.2013
comment
так что теперь пытаюсь понять в какой части рельсов находятся тесты для уведомлений - person Fivell; 08.02.2013
comment
Награда должна быть твоей! во всяком случае, я ценю это :) - person Dmitry Dedov; 12.02.2013

Инструментарий Rails работает, обертывая запрос на металлическом уровне стойки и записывая события для различных метрик. В обоих случаях весь блок должен быть обернут и отслежен стандартной аппаратурой.

Единственная разница, которую я вижу после изучения источника, заключается в вызове save() по сравнению с save!(). Похоже, что базовые подписки на события метода в ActiveRecord могут вести себя по-разному.

Попробуйте изменить свой пример response_with(), чтобы использовать сохранение вместо сохранения! и посмотрите, правильно ли он записывает db_runtime? Если это так, то это ошибка Rails, и вы можете обойти ее, имитируя сохранение! функции с помощью сохранения.

person Winfield    schedule 02.02.2013
comment
Я тоже озадачен. Извините, что не получилось. - person Winfield; 02.02.2013
comment
Уинфилд! Помогите разобраться в чем дело!)) - person Fivell; 05.02.2013

ОБНОВИТЬ:

Это не просто и требует некоторой настройки вокруг ..

Нет, если вы не напишете свой собственный Railtie, чтобы подключиться к этому, как Active Record, но это немного сложнее, чем копирование того, что есть у Active Record...

Но вот как это делается:

1) Подписчик журналов

2) Railtie

3) Среда выполнения контроллера

Я надеюсь, что вы получили намек на то, как начать вникать в это.

Ваше здоровье!

person My God    schedule 07.02.2013
comment
на самом деле это похоже на ошибку в рельсах - person Fivell; 07.02.2013