Resque正在返回Mysql2 ::错误:关闭MySQL连接:显示来自`users`的字段

时间:2012-03-03 02:56:14

标签: ruby-on-rails-3 resque

Resque正在返回Mysql2 ::错误:关闭MySQL连接:显示来自users

的字段
Worker
    8608f362-819b-4c15-b42b-69c4df00d27b:1 on low at about 16 hours ago 
Class
    AddLiveView
Arguments

    4383
    {"remote_ip"=>"184.72.47.71", "expires"=>true}

Exception
    ActiveRecord::StatementInvalid
Error
    Mysql2::Error: closed MySQL connection: SHOW FIELDS FROM `users`

    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/connection_adapters/mysql2_adapter.rb:283:in `query'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/connection_adapters/mysql2_adapter.rb:283:in `block in execute'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/connection_adapters/abstract_adapter.rb:244:in `block in log'
    /app/vendor/bundle/ruby/1.9.1/gems/activesupport-3.1.3/lib/active_support/notifications/instrumenter.rb:21:in `instrument'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/connection_adapters/abstract_adapter.rb:239:in `log'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/connection_adapters/mysql2_adapter.rb:283:in `execute'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/connection_adapters/mysql2_adapter.rb:473:in `columns'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:95:in `block (2 levels) in initialize'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:185:in `with_connection'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:92:in `block in initialize'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:106:in `yield'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:106:in `default'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:106:in `block in initialize'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/base.rb:717:in `yield'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/base.rb:717:in `default'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/base.rb:717:in `columns_hash'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/locking/optimistic.rb:145:in `locking_enabled?'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/relation.rb:110:in `to_a'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/relation/finder_methods.rb:376:in `find_first'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/relation/finder_methods.rb:122:in `first'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/associations/singular_association.rb:42:in `find_target'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/associations/association.rb:146:in `load_target'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/associations/association.rb:56:in `reload'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/associations/singular_association.rb:9:in `reader'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.1.3/lib/active_record/associations/builder/association.rb:41:in `block in define_readers'
    /app/app/workers/add_live_view.rb:24:in `block in perform'
    /usr/local/lib/ruby/1.9.1/timeout.rb:58:in `timeout'
    /app/app/workers/add_live_view.rb:13:in `perform'

我的工人班看起来像:

class AddLiveView
  @queue = :low

  def self.perform(song_id, options)
    begin
      song = Song.find(song_id)
      current_user = User.find(options['current_user_id']) if !options['expires']
    rescue
      puts "Error #{$!}"
    end

    begin
      Timeout.timeout(30.seconds) do
        if options['expires']
          # live_view = LiveView.add_live_view_that_expires(song, options['remote_ip'])
          ip_to_country = IpToCountry.where('ip_to_countries.ip_number_to >= INET_ATON(?)', options['remote_ip']).order('ip_number_to ASC').limit(1).first

          live_view = LiveView.new(:live_viewable => song, :live_viewable_category => 'View', :expires => true, :expires_at => 1.month.from_now, :ip => options['remote_ip'], :country_name => ip_to_country.country_name, :iso_two_letter_country_code => ip_to_country.iso_two_letter_country_code)

          if live_view.save
            Pusher["#{song.class.to_s.underscore}_#{song.id}"].trigger('live_view', {
              :user          => nil,
              :live_viewable => live_view.live_viewable,
              :artist        => live_view.live_viewable.user
            })

            # We do this in the worker, because we want the live_view object to exist when we push it to our notification service
            # Only keep data from last 30 days
            LiveView.where('live_views.expires = ? AND live_views.expires_at < ?', true, Date.today).destroy_all
          end
        else
          # ... do something else here ... 
        end
      end
    rescue Timeout::Error
    end
  end
end

在控制台中,我尝试通过以下方式手动执行:

song = Song.find(4383)
ip_to_country = IpToCountry.where('ip_to_countries.ip_number_to >= INET_ATON(?)', '184.72.47.71').order('ip_number_to ASC').limit(1).first
live_view = LiveView.new(:live_viewable => song, :live_viewable_category => 'View', :expires => true, :expires_at => 1.month.from_now, :ip => '184.72.47.71', :country_name => ip_to_country.country_name, :iso_two_letter_country_code => ip_to_country.iso_two_letter_country_code)
live_view.save
live_view.live_viewable.user

一切正常!为什么错误出现在生产中?这可能是因为有很多连接同时命中数据库并且达到了超时限制吗?

1 个答案:

答案 0 :(得分:5)

  

这可能是因为有很多连接同时命中数据库并且达到了超时限制吗?

那可能就是这样。您可以在Rails的控制台中轻松演示类似的东西。

$ rails console
Loading development environment (Rails 3.2.2)
1.9.3-p125 :001 > require 'timeout'
 => true
1.9.3-p125 :002 > Timeout.timeout(1) { User.find_by_sql('SELECT sleep(2) FROM users;') }
  User Load (974.4ms)  SELECT sleep(2) FROM users;
: execution expired: SELECT sleep(2) FROM users;
ActiveRecord::StatementInvalid: : execution expired: SELECT sleep(2) FROM users;
        from /Users/sluukkonen/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:243:in `query'
# Skip the rest of the backtrace...

在此之后,每次查询数据库都会引发Mysql2 :: Error,因为连接已关闭。

1.9.3-p125 :003 > User.count
Mysql2::Error: closed MySQL connection: SHOW FULL FIELDS FROM `users`
ActiveRecord::StatementInvalid: Mysql2::Error: closed MySQL connection: SHOW FULL FIELDS FROM `users`
    from /Users/sluukkonen/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:243:in `query'
# Again, skip the rest of the backtrace..

我不确定预期的行为是什么,所以我不能说Mysql2或ActiveRecord中是否有错误,但是使用带有pg gem的PostgreSQL并没有表现出类似的行为(后续查询正常执行) 。

reconnect: true添加到您的database.yml应该可以解决问题,但请注意添加它的caveats