在 Heroku 上使用 Resque 无法进行后台作业
Not working a background job with using Resque on Heroku
我的 rails 应用程序有一份工作(使用 Active Job
)。我使用 resque
和 resque-scheduler
gem 来排队后端。
我想在 Heroku 上使用 Resque 将我的 rails 应用程序连接到 redis-to-go 服务器,但我在日志中收到许多错误消息,如下所示:
2019-12-01T12:04:00.942767+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-01T12:04:00+00:00: Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)
2019-12-01T12:04:01.945657+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-01T12:04:01+00:00: Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)
2019-12-01T12:04:02.990485+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-01T12:04:02+00:00: Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)
2019-12-01T12:04:04.004590+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-01T12:04:04+00:00: Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)
2019-12-01T12:04:05.012344+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-01T12:04:05+00:00: Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)
一切都适用于开发和生产环境,但不适用于 Heroku。我发现了很多类似问题的问题,但他们的解决方案对我没有帮助。
我在 establish_connection
方法中从 redis
gem 收到一条错误消息 Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)
。但是当我从 rails 控制台中找出必要的值时,我明白了。
$ heroku run rails console
Loading production environment (Rails 5.2.3)
irb(main):001:0> Resque.redis
=> #<Resque::DataStore:0x00005643758bd968 @redis=<Redis::Namespace v1.6.0 with client v4.1.2 for redis://spinyfin.redistogo.com:11302/0/resque>, @queue_access=#<Resque::DataStore::QueueAccess:0x00005643758bd8f0 @redis=<Redis::Namespace v1.6.0 with client v4.1.2 for redis://spinyfin.redistogo.com:11302/0/resque>>, @failed_queue_access=#<Resque::DataStore::FailedQueueAccess:0x00005643758bd8c8 @redis=<Redis::Namespace v1.6.0 with client v4.1.2 for redis://spinyfin.redistogo.com:11302/0/resque>>, @workers=#<Resque::DataStore::Workers:0x00005643758bd8a0 @redis=<Redis::Namespace v1.6.0 with client v4.1.2 for redis://spinyfin.redistogo.com:11302/0/resque>>, @stats_access=#<Resque::DataStore::StatsAccess:0x00005643758bd878 @redis=<Redis::Namespace v1.6.0 with client v4.1.2 for redis://spinyfin.redistogo.com:11302/0/resque>>>
irb(main):002:0> REDIS._client
=> #<Redis::Client:0x00005643758be9f8 @options={:url=>"redis://redistogo:4822b22abf6b11bd0830af5f5797c0fb@spinyfin.redistogo.com:11302/", :scheme=>"redis", :host=>"spinyfin.redistogo.com", :port=>11302, :path=>nil, :timeout=>5.0, :password=>"4822b22abf6b11bd0830af5f5797c0fb", :db=>0, :driver=>Redis::Connection::Ruby, :id=>nil, :tcp_keepalive=>0, :reconnect_attempts=>1, :reconnect_delay=>0.0, :reconnect_delay_max=>0.5, :inherit_socket=>false, :role=>:master, :connect_timeout=>5.0, :read_timeout=>5.0, :write_timeout=>5.0, :_parsed=>true}, @reconnect=true, @logger=nil, @connection=nil, @command_map={}, @pending_reads=0, @connector=#<Redis::Client::Connector:0x00005643758bdc60 @options={:url=>"redis://redistogo:4822b22abf6b11bd0830af5f5797c0fb@spinyfin.redistogo.com:11302/", :scheme=>"redis", :host=>"spinyfin.redistogo.com", :port=>11302, :path=>nil, :timeout=>5.0, :password=>"4822b22abf6b11bd0830af5f5797c0fb", :db=>0, :driver=>Redis::Connection::Ruby, :id=>nil, :tcp_keepalive=>0, :reconnect_attempts=>1, :reconnect_delay=>0.0, :reconnect_delay_max=>0.5, :inherit_socket=>false, :role=>:master, :connect_timeout=>5.0, :read_timeout=>5.0, :write_timeout=>5.0, :_parsed=>true}>>
此外,我知道 resque
和 resque-scheduler
gems 的设置在 Heroku 上重新启动我的应用程序后工作正常,但由于某种原因 Resque 连接到 localhost:6379
而不是 redis -去服务器。你有什么想法,为什么会这样?我该如何解决这个问题?
我已经在下面提供了关于我的设置、使用 gems 等的必要信息。
============================================= ============================
heroku restart
之后的控制台日志
https://pastebin.com/E9YkxeEP(正文限于 30000 个字符,抱歉)
Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'bootsnap', '>= 1.1.0', require: false
gem 'bootstrap', '~> 4.3.1'
gem 'faker'
gem 'foreman'
gem 'jquery-rails'
gem 'local_time'
gem 'pg', '>= 0.18', '< 2.0'
gem 'puma', '~> 3.11'
gem 'rails', '~> 5.2.3'
gem 'redis'
gem 'resque'
gem 'resque-scheduler'
gem 'resque-scheduler-web'
gem 'resque-web', require: 'resque_web'
gem 'sass-rails', '~> 5.0'
gem 'turbolinks', '~> 5'
gem 'uglifier', '>= 1.3.0'
group :development, :test do
gem 'action-cable-testing'
gem 'byebug', platforms: %i[mri mingw x64_mingw]
gem 'factory_bot_rails'
gem 'pry-rails'
gem 'rails-controller-testing'
gem 'rspec-rails', '~> 3.8'
gem 'rubocop'
gem 'timecop'
end
group :development do
gem 'listen', '>= 3.0.5', '< 3.2'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem 'web-console', '>= 3.3.0'
end
gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]
Gemfile.lock
GEM
remote: https://rubygems.org/
specs:
action-cable-testing (0.6.0)
actioncable (>= 5.0)
actioncable (5.2.3)
actionpack (= 5.2.3)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailer (5.2.3)
actionpack (= 5.2.3)
actionview (= 5.2.3)
activejob (= 5.2.3)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.2.3)
actionview (= 5.2.3)
activesupport (= 5.2.3)
rack (~> 2.0)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.2.3)
activesupport (= 5.2.3)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.2.3)
activesupport (= 5.2.3)
globalid (>= 0.3.6)
activemodel (5.2.3)
activesupport (= 5.2.3)
activerecord (5.2.3)
activemodel (= 5.2.3)
activesupport (= 5.2.3)
arel (>= 9.0)
activestorage (5.2.3)
actionpack (= 5.2.3)
activerecord (= 5.2.3)
marcel (~> 0.3.1)
activesupport (5.2.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
arel (9.0.0)
ast (2.4.0)
autoprefixer-rails (9.6.1.1)
execjs
bindex (0.8.1)
bootsnap (1.4.5)
msgpack (~> 1.0)
bootstrap (4.3.1)
autoprefixer-rails (>= 9.1.0)
popper_js (>= 1.14.3, < 2)
sassc-rails (>= 2.0.0)
builder (3.2.3)
byebug (11.0.1)
coderay (1.1.2)
coffee-rails (5.0.0)
coffee-script (>= 2.2.0)
railties (>= 5.2.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.12.2)
commonjs (0.2.7)
concurrent-ruby (1.1.5)
crass (1.0.4)
diff-lcs (1.3)
erubi (1.8.0)
et-orbi (1.2.2)
tzinfo
execjs (2.7.0)
factory_bot (5.1.0)
activesupport (>= 4.2.0)
factory_bot_rails (5.1.0)
factory_bot (~> 5.1.0)
railties (>= 4.2.0)
faker (1.9.3)
i18n (>= 0.7)
ffi (1.11.1)
font-awesome-sass (5.11.2)
sassc (>= 1.11)
foreman (0.86.0)
fugit (1.3.3)
et-orbi (~> 1.1, >= 1.1.8)
raabro (~> 1.1)
globalid (0.4.2)
activesupport (>= 4.2.0)
i18n (1.6.0)
concurrent-ruby (~> 1.0)
jaro_winkler (1.5.3)
jquery-rails (4.3.5)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
less (2.6.0)
commonjs (~> 0.2.7)
less-rails (2.8.0)
actionpack (>= 4.0)
less (~> 2.6.0)
sprockets (> 2, < 4)
tilt
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
local_time (2.1.0)
loofah (2.2.3)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
method_source (0.9.2)
mimemagic (0.3.3)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
minitest (5.11.3)
mono_logger (1.1.0)
msgpack (1.3.1)
multi_json (1.14.1)
mustermann (1.0.3)
nio4r (2.5.1)
nokogiri (1.10.4)
mini_portile2 (~> 2.4.0)
parallel (1.17.0)
parser (2.6.3.0)
ast (~> 2.4.0)
pg (1.1.4)
popper_js (1.14.5)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry-rails (0.3.9)
pry (>= 0.10.4)
puma (3.12.1)
raabro (1.1.6)
rack (2.0.7)
rack-protection (2.0.7)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails (5.2.3)
actioncable (= 5.2.3)
actionmailer (= 5.2.3)
actionpack (= 5.2.3)
actionview (= 5.2.3)
activejob (= 5.2.3)
activemodel (= 5.2.3)
activerecord (= 5.2.3)
activestorage (= 5.2.3)
activesupport (= 5.2.3)
bundler (>= 1.3.0)
railties (= 5.2.3)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.4)
actionpack (>= 5.0.1.x)
actionview (>= 5.0.1.x)
activesupport (>= 5.0.1.x)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.2.0)
loofah (~> 2.2, >= 2.2.2)
railties (5.2.3)
actionpack (= 5.2.3)
activesupport (= 5.2.3)
method_source
rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0)
rainbow (3.0.0)
rake (12.3.3)
rb-fsevent (0.10.3)
rb-inotify (0.10.0)
ffi (~> 1.0)
redis (4.1.2)
redis-namespace (1.6.0)
redis (>= 3.0.4)
resque (2.0.0)
mono_logger (~> 1.0)
multi_json (~> 1.0)
redis-namespace (~> 1.6)
sinatra (>= 0.9.2)
vegas (~> 0.1.2)
resque-scheduler (4.4.0)
mono_logger (~> 1.0)
redis (>= 3.3)
resque (>= 1.26)
rufus-scheduler (~> 3.2)
resque-scheduler-web (1.1.0)
resque-scheduler (~> 4.0)
resque-web (~> 0.0.8)
resque-web (0.0.12)
coffee-rails
font-awesome-sass
jquery-rails
resque
sass-rails
twitter-bootstrap-rails
rspec-core (3.8.2)
rspec-support (~> 3.8.0)
rspec-expectations (3.8.4)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-mocks (3.8.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-rails (3.8.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.8.0)
rspec-support (~> 3.8.0)
rspec-support (3.8.2)
rubocop (0.72.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.6)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 1.7)
ruby-progressbar (1.10.1)
ruby_dep (1.5.0)
rufus-scheduler (3.6.0)
fugit (~> 1.1, >= 1.1.6)
sass (3.7.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sass-rails (5.1.0)
railties (>= 5.2.0)
sass (~> 3.1)
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
sassc (2.2.0)
ffi (~> 1.9)
sassc-rails (2.1.2)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
sinatra (2.0.7)
mustermann (~> 1.0)
rack (~> 2.0)
rack-protection (= 2.0.7)
tilt (~> 2.0)
spring (2.1.0)
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
thor (0.20.3)
thread_safe (0.3.6)
tilt (2.0.9)
timecop (0.9.1)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
twitter-bootstrap-rails (4.0.0)
actionpack (~> 5.0, >= 5.0.1)
execjs (~> 2.7)
less-rails (~> 2.8, >= 2.8.0)
railties (~> 5.0, >= 5.0.1)
tzinfo (1.2.5)
thread_safe (~> 0.1)
uglifier (4.1.20)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.6.0)
vegas (0.1.11)
rack (>= 1.0.0)
web-console (3.7.0)
actionview (>= 5.0)
activemodel (>= 5.0)
bindex (>= 0.4.0)
railties (>= 5.0)
websocket-driver (0.7.1)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.4)
PLATFORMS
ruby
DEPENDENCIES
action-cable-testing
bootsnap (>= 1.1.0)
bootstrap (~> 4.3.1)
byebug
factory_bot_rails
faker
foreman
jquery-rails
listen (>= 3.0.5, < 3.2)
local_time
pg (>= 0.18, < 2.0)
pry-rails
puma (~> 3.11)
rails (~> 5.2.3)
rails-controller-testing
redis
resque
resque-scheduler
resque-scheduler-web
resque-web
rspec-rails (~> 3.8)
rubocop
sass-rails (~> 5.0)
spring
spring-watcher-listen (~> 2.0.0)
timecop
turbolinks (~> 5)
tzinfo-data
uglifier (>= 1.3.0)
web-console (>= 3.3.0)
BUNDLED WITH
1.17.2
Procfile
worker: RESQUE_SCHEDULER_INTERVAL=1 INTERVAL=1 QUEUE=leramiz* COUNT=1 TERM_CHILD=1 RESQUE_TERM_TIMEOUT=10 bundle exec rake resque:schedule_and_work
lib/tasks/resque.rake
require 'resque/tasks'
require 'resque/scheduler/tasks'
task 'resque:preload' => :environment
namespace :resque do
#
# https://grosser.it/2012/04/14/resque-scheduler-on-heroku-without-extra-workers/
desc 'schedule and work, so we only need 1 dyno'
task :schedule_and_work do
if Process.respond_to?(:fork)
if Process.fork
sh('rake environment resque:work')
else
sh('rake resque:scheduler')
Process.wait
end
else # windows
pid = Process.spawn 'rake environment resque:work'
Rake::Task['resque:scheduler'].invoke
Process.wait(pid)
end
end
task :setup do
require 'resque'
end
task setup_schedule: :setup do
require 'resque-scheduler'
end
task scheduler: :setup_schedule
end
config/initializers/resque.rb
require 'resque/server'
if Rails.env.development?
Resque.redis = Redis.new(host: 'localhost', port: '6379')
else
REDIS = Redis.new(url: ENV['REDISTOGO_URL'])
Resque.redis = REDIS
end
Resque.logger = Logger.new(Rails.root.join('log', "#{Rails.env}_resque.log"))
Resque.logger.level = Logger::DEBUG
config/environments/production.rb
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
# or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
# config.require_master_key = true
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
# Compress JavaScripts and CSS.
config.assets.js_compressor = config.assets.js_compressor = Uglifier.new(harmony: true)
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = 'http://assets.example.com'
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Mount Action Cable outside main process or domain
# config.action_cable.mount_path = nil
config.action_cable.url = 'wss://cuurjol-leramiz.herokuapp.com/cable'
config.action_cable.allowed_request_origins = %w[http://cuurjol-leramiz.herokuapp.com/cable https://cuurjol-leramiz.herokuapp.com/cable]
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = :debug
# Prepend all log lines with the following tags.
config.log_tags = [:request_id]
# Use a different cache store in production.
config.cache_store = :redis_cache_store, { url: ENV['REDISTOGO_URL'] }
# Use a real queuing backend for Active Job (and separate queues per environment)
config.active_job.queue_adapter = :resque
config.active_job.queue_name_prefix = "leramiz_#{Rails.env}"
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Use a different logger for distributed setups.
# require 'syslog/logger'
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
if ENV['RAILS_LOG_TO_STDOUT'].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
end
app/jobs/destroy_private_job.rb
class DestroyPrivateRoomJob < ApplicationJob
queue_as :default
def perform(room)
users = room.users.to_a
room.destroy
ActionCable.server.broadcast('room_management_channel', room: room.as_json(only: %i[id is_private token]),
status: 'destroyed')
room_users_list = { room_id: room.id, users: room.users.uniq.as_json(only: :nickname) }
ActionCable.server.broadcast('room_users_list_channel', room_users_list: room_users_list)
users.each do |user|
Rails.cache.write("message_for_user:#{user.id}", "Expiration time for Room ##{room.id} is over")
end
end
end
他们的文档使您看起来只需要为 redis 设置 URL 而不是 redis https://github.com/resque/resque/blob/master/README.markdown#configuration
的实例
lib/tasks/resque.rake 文件中有一段代码:
task :schedule_and_work do
if Process.respond_to?(:fork)
if Process.fork
sh('rake environment resque:work')
else
sh('rake resque:scheduler')
Process.wait
end
else # windows
pid = Process.spawn 'rake environment resque:work'
Rake::Task['resque:scheduler'].invoke
Process.wait(pid)
end
end
将其替换为以下内容:
task :schedule_and_work do
if Process.respond_to?(:fork)
if Process.fork
sh('rake environment resque:work')
else
sh('rake environment resque:scheduler')
Process.wait
end
else # windows
pid = Process.spawn 'rake environment resque:work'
Rake::Task['environment resque:scheduler'].invoke
Process.wait(pid)
end
end
它们之间的区别是我为resque:scheduler
rake任务添加了一个词environment
。我不知道为什么它如此重要,但它确实有效。之后我得到正确的消息而不是错误消息:
2019-12-03T20:24:48.131365+00:00 app[worker.1]: rake environment resque:work
2019-12-03T20:24:48.131606+00:00 app[worker.1]: rake environment resque:scheduler
2019-12-03T20:24:50.913986+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Starting
2019-12-03T20:24:50.914027+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Master scheduler
2019-12-03T20:24:50.914137+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Reloading Schedule
2019-12-03T20:24:50.918571+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Loading Schedule
2019-12-03T20:24:50.919477+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Schedule empty! Set Resque.schedule
2019-12-03T20:24:50.919543+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Schedules Loaded
2019-12-03T20:24:50.920549+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Processing Delayed Items
我的 rails 应用程序有一份工作(使用 Active Job
)。我使用 resque
和 resque-scheduler
gem 来排队后端。
我想在 Heroku 上使用 Resque 将我的 rails 应用程序连接到 redis-to-go 服务器,但我在日志中收到许多错误消息,如下所示:
2019-12-01T12:04:00.942767+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-01T12:04:00+00:00: Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)
2019-12-01T12:04:01.945657+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-01T12:04:01+00:00: Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)
2019-12-01T12:04:02.990485+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-01T12:04:02+00:00: Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)
2019-12-01T12:04:04.004590+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-01T12:04:04+00:00: Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)
2019-12-01T12:04:05.012344+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-01T12:04:05+00:00: Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)
一切都适用于开发和生产环境,但不适用于 Heroku。我发现了很多类似问题的问题,但他们的解决方案对我没有帮助。
我在 establish_connection
方法中从 redis
gem 收到一条错误消息 Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED)
。但是当我从 rails 控制台中找出必要的值时,我明白了。
$ heroku run rails console
Loading production environment (Rails 5.2.3)
irb(main):001:0> Resque.redis
=> #<Resque::DataStore:0x00005643758bd968 @redis=<Redis::Namespace v1.6.0 with client v4.1.2 for redis://spinyfin.redistogo.com:11302/0/resque>, @queue_access=#<Resque::DataStore::QueueAccess:0x00005643758bd8f0 @redis=<Redis::Namespace v1.6.0 with client v4.1.2 for redis://spinyfin.redistogo.com:11302/0/resque>>, @failed_queue_access=#<Resque::DataStore::FailedQueueAccess:0x00005643758bd8c8 @redis=<Redis::Namespace v1.6.0 with client v4.1.2 for redis://spinyfin.redistogo.com:11302/0/resque>>, @workers=#<Resque::DataStore::Workers:0x00005643758bd8a0 @redis=<Redis::Namespace v1.6.0 with client v4.1.2 for redis://spinyfin.redistogo.com:11302/0/resque>>, @stats_access=#<Resque::DataStore::StatsAccess:0x00005643758bd878 @redis=<Redis::Namespace v1.6.0 with client v4.1.2 for redis://spinyfin.redistogo.com:11302/0/resque>>>
irb(main):002:0> REDIS._client
=> #<Redis::Client:0x00005643758be9f8 @options={:url=>"redis://redistogo:4822b22abf6b11bd0830af5f5797c0fb@spinyfin.redistogo.com:11302/", :scheme=>"redis", :host=>"spinyfin.redistogo.com", :port=>11302, :path=>nil, :timeout=>5.0, :password=>"4822b22abf6b11bd0830af5f5797c0fb", :db=>0, :driver=>Redis::Connection::Ruby, :id=>nil, :tcp_keepalive=>0, :reconnect_attempts=>1, :reconnect_delay=>0.0, :reconnect_delay_max=>0.5, :inherit_socket=>false, :role=>:master, :connect_timeout=>5.0, :read_timeout=>5.0, :write_timeout=>5.0, :_parsed=>true}, @reconnect=true, @logger=nil, @connection=nil, @command_map={}, @pending_reads=0, @connector=#<Redis::Client::Connector:0x00005643758bdc60 @options={:url=>"redis://redistogo:4822b22abf6b11bd0830af5f5797c0fb@spinyfin.redistogo.com:11302/", :scheme=>"redis", :host=>"spinyfin.redistogo.com", :port=>11302, :path=>nil, :timeout=>5.0, :password=>"4822b22abf6b11bd0830af5f5797c0fb", :db=>0, :driver=>Redis::Connection::Ruby, :id=>nil, :tcp_keepalive=>0, :reconnect_attempts=>1, :reconnect_delay=>0.0, :reconnect_delay_max=>0.5, :inherit_socket=>false, :role=>:master, :connect_timeout=>5.0, :read_timeout=>5.0, :write_timeout=>5.0, :_parsed=>true}>>
此外,我知道 resque
和 resque-scheduler
gems 的设置在 Heroku 上重新启动我的应用程序后工作正常,但由于某种原因 Resque 连接到 localhost:6379
而不是 redis -去服务器。你有什么想法,为什么会这样?我该如何解决这个问题?
我已经在下面提供了关于我的设置、使用 gems 等的必要信息。
============================================= ============================
heroku restart
https://pastebin.com/E9YkxeEP(正文限于 30000 个字符,抱歉)
Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'bootsnap', '>= 1.1.0', require: false
gem 'bootstrap', '~> 4.3.1'
gem 'faker'
gem 'foreman'
gem 'jquery-rails'
gem 'local_time'
gem 'pg', '>= 0.18', '< 2.0'
gem 'puma', '~> 3.11'
gem 'rails', '~> 5.2.3'
gem 'redis'
gem 'resque'
gem 'resque-scheduler'
gem 'resque-scheduler-web'
gem 'resque-web', require: 'resque_web'
gem 'sass-rails', '~> 5.0'
gem 'turbolinks', '~> 5'
gem 'uglifier', '>= 1.3.0'
group :development, :test do
gem 'action-cable-testing'
gem 'byebug', platforms: %i[mri mingw x64_mingw]
gem 'factory_bot_rails'
gem 'pry-rails'
gem 'rails-controller-testing'
gem 'rspec-rails', '~> 3.8'
gem 'rubocop'
gem 'timecop'
end
group :development do
gem 'listen', '>= 3.0.5', '< 3.2'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem 'web-console', '>= 3.3.0'
end
gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]
Gemfile.lock
GEM
remote: https://rubygems.org/
specs:
action-cable-testing (0.6.0)
actioncable (>= 5.0)
actioncable (5.2.3)
actionpack (= 5.2.3)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailer (5.2.3)
actionpack (= 5.2.3)
actionview (= 5.2.3)
activejob (= 5.2.3)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.2.3)
actionview (= 5.2.3)
activesupport (= 5.2.3)
rack (~> 2.0)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.2.3)
activesupport (= 5.2.3)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.2.3)
activesupport (= 5.2.3)
globalid (>= 0.3.6)
activemodel (5.2.3)
activesupport (= 5.2.3)
activerecord (5.2.3)
activemodel (= 5.2.3)
activesupport (= 5.2.3)
arel (>= 9.0)
activestorage (5.2.3)
actionpack (= 5.2.3)
activerecord (= 5.2.3)
marcel (~> 0.3.1)
activesupport (5.2.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
arel (9.0.0)
ast (2.4.0)
autoprefixer-rails (9.6.1.1)
execjs
bindex (0.8.1)
bootsnap (1.4.5)
msgpack (~> 1.0)
bootstrap (4.3.1)
autoprefixer-rails (>= 9.1.0)
popper_js (>= 1.14.3, < 2)
sassc-rails (>= 2.0.0)
builder (3.2.3)
byebug (11.0.1)
coderay (1.1.2)
coffee-rails (5.0.0)
coffee-script (>= 2.2.0)
railties (>= 5.2.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.12.2)
commonjs (0.2.7)
concurrent-ruby (1.1.5)
crass (1.0.4)
diff-lcs (1.3)
erubi (1.8.0)
et-orbi (1.2.2)
tzinfo
execjs (2.7.0)
factory_bot (5.1.0)
activesupport (>= 4.2.0)
factory_bot_rails (5.1.0)
factory_bot (~> 5.1.0)
railties (>= 4.2.0)
faker (1.9.3)
i18n (>= 0.7)
ffi (1.11.1)
font-awesome-sass (5.11.2)
sassc (>= 1.11)
foreman (0.86.0)
fugit (1.3.3)
et-orbi (~> 1.1, >= 1.1.8)
raabro (~> 1.1)
globalid (0.4.2)
activesupport (>= 4.2.0)
i18n (1.6.0)
concurrent-ruby (~> 1.0)
jaro_winkler (1.5.3)
jquery-rails (4.3.5)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
less (2.6.0)
commonjs (~> 0.2.7)
less-rails (2.8.0)
actionpack (>= 4.0)
less (~> 2.6.0)
sprockets (> 2, < 4)
tilt
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
local_time (2.1.0)
loofah (2.2.3)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
method_source (0.9.2)
mimemagic (0.3.3)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
minitest (5.11.3)
mono_logger (1.1.0)
msgpack (1.3.1)
multi_json (1.14.1)
mustermann (1.0.3)
nio4r (2.5.1)
nokogiri (1.10.4)
mini_portile2 (~> 2.4.0)
parallel (1.17.0)
parser (2.6.3.0)
ast (~> 2.4.0)
pg (1.1.4)
popper_js (1.14.5)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry-rails (0.3.9)
pry (>= 0.10.4)
puma (3.12.1)
raabro (1.1.6)
rack (2.0.7)
rack-protection (2.0.7)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails (5.2.3)
actioncable (= 5.2.3)
actionmailer (= 5.2.3)
actionpack (= 5.2.3)
actionview (= 5.2.3)
activejob (= 5.2.3)
activemodel (= 5.2.3)
activerecord (= 5.2.3)
activestorage (= 5.2.3)
activesupport (= 5.2.3)
bundler (>= 1.3.0)
railties (= 5.2.3)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.4)
actionpack (>= 5.0.1.x)
actionview (>= 5.0.1.x)
activesupport (>= 5.0.1.x)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.2.0)
loofah (~> 2.2, >= 2.2.2)
railties (5.2.3)
actionpack (= 5.2.3)
activesupport (= 5.2.3)
method_source
rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0)
rainbow (3.0.0)
rake (12.3.3)
rb-fsevent (0.10.3)
rb-inotify (0.10.0)
ffi (~> 1.0)
redis (4.1.2)
redis-namespace (1.6.0)
redis (>= 3.0.4)
resque (2.0.0)
mono_logger (~> 1.0)
multi_json (~> 1.0)
redis-namespace (~> 1.6)
sinatra (>= 0.9.2)
vegas (~> 0.1.2)
resque-scheduler (4.4.0)
mono_logger (~> 1.0)
redis (>= 3.3)
resque (>= 1.26)
rufus-scheduler (~> 3.2)
resque-scheduler-web (1.1.0)
resque-scheduler (~> 4.0)
resque-web (~> 0.0.8)
resque-web (0.0.12)
coffee-rails
font-awesome-sass
jquery-rails
resque
sass-rails
twitter-bootstrap-rails
rspec-core (3.8.2)
rspec-support (~> 3.8.0)
rspec-expectations (3.8.4)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-mocks (3.8.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-rails (3.8.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.8.0)
rspec-support (~> 3.8.0)
rspec-support (3.8.2)
rubocop (0.72.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.6)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 1.7)
ruby-progressbar (1.10.1)
ruby_dep (1.5.0)
rufus-scheduler (3.6.0)
fugit (~> 1.1, >= 1.1.6)
sass (3.7.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sass-rails (5.1.0)
railties (>= 5.2.0)
sass (~> 3.1)
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
sassc (2.2.0)
ffi (~> 1.9)
sassc-rails (2.1.2)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
sinatra (2.0.7)
mustermann (~> 1.0)
rack (~> 2.0)
rack-protection (= 2.0.7)
tilt (~> 2.0)
spring (2.1.0)
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
thor (0.20.3)
thread_safe (0.3.6)
tilt (2.0.9)
timecop (0.9.1)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
twitter-bootstrap-rails (4.0.0)
actionpack (~> 5.0, >= 5.0.1)
execjs (~> 2.7)
less-rails (~> 2.8, >= 2.8.0)
railties (~> 5.0, >= 5.0.1)
tzinfo (1.2.5)
thread_safe (~> 0.1)
uglifier (4.1.20)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.6.0)
vegas (0.1.11)
rack (>= 1.0.0)
web-console (3.7.0)
actionview (>= 5.0)
activemodel (>= 5.0)
bindex (>= 0.4.0)
railties (>= 5.0)
websocket-driver (0.7.1)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.4)
PLATFORMS
ruby
DEPENDENCIES
action-cable-testing
bootsnap (>= 1.1.0)
bootstrap (~> 4.3.1)
byebug
factory_bot_rails
faker
foreman
jquery-rails
listen (>= 3.0.5, < 3.2)
local_time
pg (>= 0.18, < 2.0)
pry-rails
puma (~> 3.11)
rails (~> 5.2.3)
rails-controller-testing
redis
resque
resque-scheduler
resque-scheduler-web
resque-web
rspec-rails (~> 3.8)
rubocop
sass-rails (~> 5.0)
spring
spring-watcher-listen (~> 2.0.0)
timecop
turbolinks (~> 5)
tzinfo-data
uglifier (>= 1.3.0)
web-console (>= 3.3.0)
BUNDLED WITH
1.17.2
Procfile
worker: RESQUE_SCHEDULER_INTERVAL=1 INTERVAL=1 QUEUE=leramiz* COUNT=1 TERM_CHILD=1 RESQUE_TERM_TIMEOUT=10 bundle exec rake resque:schedule_and_work
lib/tasks/resque.rake
require 'resque/tasks'
require 'resque/scheduler/tasks'
task 'resque:preload' => :environment
namespace :resque do
#
# https://grosser.it/2012/04/14/resque-scheduler-on-heroku-without-extra-workers/
desc 'schedule and work, so we only need 1 dyno'
task :schedule_and_work do
if Process.respond_to?(:fork)
if Process.fork
sh('rake environment resque:work')
else
sh('rake resque:scheduler')
Process.wait
end
else # windows
pid = Process.spawn 'rake environment resque:work'
Rake::Task['resque:scheduler'].invoke
Process.wait(pid)
end
end
task :setup do
require 'resque'
end
task setup_schedule: :setup do
require 'resque-scheduler'
end
task scheduler: :setup_schedule
end
config/initializers/resque.rb
require 'resque/server'
if Rails.env.development?
Resque.redis = Redis.new(host: 'localhost', port: '6379')
else
REDIS = Redis.new(url: ENV['REDISTOGO_URL'])
Resque.redis = REDIS
end
Resque.logger = Logger.new(Rails.root.join('log', "#{Rails.env}_resque.log"))
Resque.logger.level = Logger::DEBUG
config/environments/production.rb
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
# or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
# config.require_master_key = true
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
# Compress JavaScripts and CSS.
config.assets.js_compressor = config.assets.js_compressor = Uglifier.new(harmony: true)
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = 'http://assets.example.com'
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Mount Action Cable outside main process or domain
# config.action_cable.mount_path = nil
config.action_cable.url = 'wss://cuurjol-leramiz.herokuapp.com/cable'
config.action_cable.allowed_request_origins = %w[http://cuurjol-leramiz.herokuapp.com/cable https://cuurjol-leramiz.herokuapp.com/cable]
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = :debug
# Prepend all log lines with the following tags.
config.log_tags = [:request_id]
# Use a different cache store in production.
config.cache_store = :redis_cache_store, { url: ENV['REDISTOGO_URL'] }
# Use a real queuing backend for Active Job (and separate queues per environment)
config.active_job.queue_adapter = :resque
config.active_job.queue_name_prefix = "leramiz_#{Rails.env}"
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Use a different logger for distributed setups.
# require 'syslog/logger'
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
if ENV['RAILS_LOG_TO_STDOUT'].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
end
app/jobs/destroy_private_job.rb
class DestroyPrivateRoomJob < ApplicationJob
queue_as :default
def perform(room)
users = room.users.to_a
room.destroy
ActionCable.server.broadcast('room_management_channel', room: room.as_json(only: %i[id is_private token]),
status: 'destroyed')
room_users_list = { room_id: room.id, users: room.users.uniq.as_json(only: :nickname) }
ActionCable.server.broadcast('room_users_list_channel', room_users_list: room_users_list)
users.each do |user|
Rails.cache.write("message_for_user:#{user.id}", "Expiration time for Room ##{room.id} is over")
end
end
end
他们的文档使您看起来只需要为 redis 设置 URL 而不是 redis https://github.com/resque/resque/blob/master/README.markdown#configuration
的实例lib/tasks/resque.rake 文件中有一段代码:
task :schedule_and_work do
if Process.respond_to?(:fork)
if Process.fork
sh('rake environment resque:work')
else
sh('rake resque:scheduler')
Process.wait
end
else # windows
pid = Process.spawn 'rake environment resque:work'
Rake::Task['resque:scheduler'].invoke
Process.wait(pid)
end
end
将其替换为以下内容:
task :schedule_and_work do
if Process.respond_to?(:fork)
if Process.fork
sh('rake environment resque:work')
else
sh('rake environment resque:scheduler')
Process.wait
end
else # windows
pid = Process.spawn 'rake environment resque:work'
Rake::Task['environment resque:scheduler'].invoke
Process.wait(pid)
end
end
它们之间的区别是我为resque:scheduler
rake任务添加了一个词environment
。我不知道为什么它如此重要,但它确实有效。之后我得到正确的消息而不是错误消息:
2019-12-03T20:24:48.131365+00:00 app[worker.1]: rake environment resque:work
2019-12-03T20:24:48.131606+00:00 app[worker.1]: rake environment resque:scheduler
2019-12-03T20:24:50.913986+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Starting
2019-12-03T20:24:50.914027+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Master scheduler
2019-12-03T20:24:50.914137+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Reloading Schedule
2019-12-03T20:24:50.918571+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Loading Schedule
2019-12-03T20:24:50.919477+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Schedule empty! Set Resque.schedule
2019-12-03T20:24:50.919543+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Schedules Loaded
2019-12-03T20:24:50.920549+00:00 app[worker.1]: resque-scheduler: [INFO] 2019-12-03T20:24:50+00:00: Processing Delayed Items