Resque с Rails 3 + Heroku + RedisToGo дает ошибку Postgresql - PullRequest
3 голосов
/ 29 марта 2012

Я пишу приложение, которое должно отправлять много писем и создает множество пользовательских уведомлений из-за этих писем. Эта задача приводит к тайм-ауту в Heroku. Чтобы решить эту проблему, я решил использовать Resque и RedistToGo.

Что я сделал, так это отправил электронное письмо (на самом деле это всего лишь одно электронное письмо, потому что мы используем Sendgrid для его обработки) и создавал уведомления с помощью работника Resque. Письмо уже создано, поэтому я отправляю его идентификатор работнику вместе со всеми получателями.

Это хорошо работает локально. На производстве, если мы не перезапустим наше приложение в Heroku, оно будет работать только один раз. Я опубликую часть моего кода и сообщение об ошибке:

#lib/tasks/resque.rake
require 'resque/tasks'

task "resque:setup" => :environment do
  ENV['QUEUE'] = '*'
end

desc "Alias for resque:work (To run workers on Heroku)"
task "jobs:work" => "resque:work"


#config/initalizers/resque.rb
ENV["REDISTOGO_URL"] ||= "redis://redistogo:some_hash@some_url:some_number/"

uri = URI.parse(ENV["REDISTOGO_URL"])
Resque.redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)

Dir["#{Rails.root}/app/workers/*.rb"].each { |file| require file }


#app/workers/massive_email_sender.rb
class MassiveEmailSender 
  @queue = :massive_email_queue

  def self.perform(email_id, recipients)
    email = Email.find(email_id.to_i)
    email.recipients = recipients
    email.send_email
  end

end

У меня есть модель Email, в которой есть after_create, который ставит работника в очередь:

class Email < ActiveRecord::Base

...

after_create :enqueue_email

  def enqueue_email
    Resque.enqueue(MassiveEmailSender, self.id, self.recipients)
  end

...

end

Эта модель электронной почты также имеет метод send_email, который делает то, что я говорил ранее

Я получаю следующее сообщение об ошибке. Я опубликую всю информацию, которую Resque дает мне:

Worker
    9dddd06a-2158-464a-b3d9-b2d16380afcf:1 on massive_email_queue at just now
    Retry or Remove
Class
    MassiveEmailSender
Arguments

    21
    ["some_email_1@gmail.com", "some_email_2@gmail.com"]

Exception
    ActiveRecord::StatementInvalid
Error
    PG::Error: SSL error: decryption failed or bad record mac : SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '"emails"'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum

    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:1139:in `async_exec'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:1139:in `exec_no_cache'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:663:in `block in exec_query'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract_adapter.rb:280:in `block in log'
    /app/vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.2/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract_adapter.rb:275:in `log'
    /app/vendor/bundle/ruby/1.9.1/gems/newrelic_rpm-3.3.2/lib/new_relic/agent/instrumentation/active_record.rb:31:in `block in log_with_newrelic_instrumentation'
    /app/vendor/bundle/ruby/1.9.1/gems/newrelic_rpm-3.3.2/lib/new_relic/agent/method_tracer.rb:242:in `trace_execution_scoped'
    /app/vendor/bundle/ruby/1.9.1/gems/newrelic_rpm-3.3.2/lib/new_relic/agent/instrumentation/active_record.rb:28:in `log_with_newrelic_instrumentation'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:662:in `exec_query'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:1264:in `column_definitions'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:858:in `columns'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/schema_cache.rb:12:in `block in initialize'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/model_schema.rb:228:in `yield'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/model_schema.rb:228:in `default'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/model_schema.rb:228:in `columns'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/model_schema.rb:237:in `columns_hash'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/relation/delegation.rb:7:in `columns_hash'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/relation/finder_methods.rb:330:in `find_one'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/relation/finder_methods.rb:311:in `find_with_ids'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/relation/finder_methods.rb:107:in `find'
    /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/querying.rb:5:in `find'
    /app/app/workers/massive_email_sender.rb:5:in `perform'

В соответствии с этим первый аргумент - это идентификатор электронной почты, а второй - список всех получателей ... именно так, как и должно быть.

Кто-нибудь может мне помочь? Спасибо!

1 Ответ

4 голосов
/ 05 мая 2012

Я столкнулся с той же проблемой. Предполагая, что вы используете Active Record, вы должны вызвать ActiveRecord::Base.establish_connection для каждого разветвленного работника Resque, чтобы убедиться, что у него нет устаревшего соединения с базой данных. Попробуйте вставить это в lib/tasks/resque.rake

task "resque:setup" => :environment do
  ENV['QUEUE'] = '*'
  Resque.after_fork = Proc.new { ActiveRecord::Base.establish_connection }
end
...