-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Simply edit this page and add your question to the bottom in the following format:
/ˈreskyo͞o/
Are you using newrelic_rpm? This is a known bug: https://github.com/resque/resque/issues/180
Whatever the root cause, https://github.com/shaiguitar/resque_stuck_queue/ can help you identify Resque issues coming up before it's too late.
In Addition, If you kill the resque in running state the job will be moved to failed queue with error Dirty Exit so you can retry that later with running queue.
And respect to stuck queues go to rails console and check Resque.workers for struck queues and delete using Resque.remove_worker(Resque.workers[n].id)
This may not be the best way, but it's an option. You can manage resque, and any other services your app runs, with foreman; by using upstart or init scripts on the remote server. See "Managing and monitoring your Ruby application with Foreman and Upstart" for a guide on getting Foreman running. Once that's done, here's a sample cap task to manage your processes:
namespace :foreman do
desc "Start the application services"
task :start, :roles => :app do
sudo "start #{application}"
end
desc "Stop the application services"
task :stop, :roles => :app do
sudo "stop #{application}"
end
desc "Restart the application services"
task :restart, :roles => :app do
run "sudo start #{application} || sudo restart #{application}"
end
desc "Display logs for a certain process - arg example: PROCESS=web-1"
task :logs, :roles => :app do
run "cd #{current_path}/log && cat #{ENV["PROCESS"]}.log"
end
desc "Export the Procfile to upstart scripts"
task :export, :roles => :app do
# 5 resque workers, 1 resque scheduler
run "cd #{release_path} && rvmsudo bundle exec foreman export upstart /etc/init -a #{application} -u #{user} -l #{shared_path}/log -f #{release_path}/Procfile.production -c worker=5,scheduler=1"
end
end
When you write a restart task for resque, you may want to think what happens to a job running at that time. If you want to make sure the job finishes properly, you must send the QUIT
signal to the existing resque worker process. This will stop the worker process gracefully.
Check out Readme and 1-x-stable Readme to learn more about how Resque workers respond to signals.
Make sure you start your workers by specifying environment
as part of your rake execution.
For example:
QUEUE=* rake environment resque:work
Some users also experience issues where Rails models are lazy-loaded in the Job execution. Due to some internal class loading wackiness, this results in LoadErrors
or Uninitialized Constant
exceptions. This can be solved by forcing ActiveRecord models to load, by creating a lib/tasks/resque.rake
# load the Rails app all the time
namespace :resque do
puts "Loading Rails environment for Resque"
task :setup => :environment do
ActiveRecord::Base.descendants.each { |klass| klass.columns }
end
end
The first way is to enqueue a job in a model's after_commit
hook.
But after_commit
solves the problem only in the model create and update use cases.
In general, a task should be put into redis only after all transactions are complete, otherwise serious problems may appear. In order to do that use the ar_after_transaction gem, which provides an after_transaction
hook whenever you need it:
ActiveRecord::Base.after_transaction do
Resque.enqueue(SyncronizationWithGithubWorker, asset.id)
end
If you want to keep the team free from worrying about transaction isolation levels,
then you should monkey patch Resque.enqueue
to be performed only after the transaction completes.
require 'ar_after_transaction'
require 'resque'
Resque.class_eval do
class << self
alias_method :enqueue_without_transaction, :enqueue
def enqueue(*args)
ActiveRecord::Base.after_transaction do
enqueue_without_transaction(*args)
end
end
end
end
Add ActiveRecord::Base.logger = Logger.new(STDOUT)
to your ruby class.
Create folder resque
inside your rails/lib. Copy files *.erb to override from /gems/resque.../lib/resque/server/views. Create softlinks from your rails/lib/... to gem path. The best way is use bash script for you development machine to create this softlinks and use your deploy.rb file to create softlinks with capistrano.
This is usually related to the web server configuration. Below are instructions for Apache and Nginx.
Rack uses the X-SendFile header to serve resque-web's UI assets out of the gem. Since your gem installation is typically located outside of your deployed project root and some web servers do not serve files outside of the project root by default for security reasons, you may need to tweak your Apache configuration.
- In your Rails application, set
config.action_dispatch.x_sendfile_header = "X-Sendfile"
. - On your web server, install the XSendFile module
- Update the appropriate Apache configuration file to enable the module and allow it to serve assets from the gem:
XSendFile on
XSendFilePath /path/to/shared/bundle
XSendFilePath allow-lists a directory from which static files are allowed to be served. This should be at least the path to where resque
is installed.
In nginx.conf, remove the asset serving module location ~* .(jpg|jpeg|png|gif|ico|css|js)$
This will server the static assets of Resque.
Else we can add path to it.
In your perform
method, add the following line:
class MyTask
def self.perform
ActiveRecord::Base.verify_active_connections!
# rest of your code
end
end
The Rails doc says the following about verify_active_connections!
:
Verify active connections and remove and disconnect connections associated with stale threads.
In your perform
method, instead of verify_active_connections!
, use:
class MyTask
def self.perform
ActiveRecord::Base.clear_active_connections!
# rest of your code
end
end
From the Rails docs on clear_active_connections!
:
Returns any connections in use by the current thread back to the pool, and also returns connections to the pool cached by threads that are no longer alive.
Add the password to your Redis.new
.
Resque.redis = Redis.new(:host => 'foo',
:port => 'foo',
:password => 'foo')
Change your routes.rb
file to authenticate your users.
#routes.rb
...
devise_for :admin_users, ActiveAdmin::Devise.config
authenticate :admin_user do #replace admin_user(s) with whatever model your users are stored in.
mount Resque::Server.new, :at => "/jobs"
end
...
If you need to be more specific with your authentication conditions, you can include them in a :constraints
block when mounting via match
method.
match "/jobs" => Resque::Server, :anchor => false, :constraints => lambda { |req|
req.env['warden'].authenticated? and req.env['warden'].user.can_view_resque?
}
Using Authlogic
Leverage Authlogic's Sinatra adapter, and refine the conditions under which a user should be allowed to access resque-web:
# lib/resque_admins.rb
require "authlogic/controller_adapters/sinatra_adapter"
class ResqueAdmins
def self.matches?(request)
Authlogic::Session::Base.controller =
Authlogic::ControllerAdapters::SinatraAdapter::Adapter.new(request)
user_session = UserSession.find
user_session && user_session.user.can_view_resque?
end
end
Add a custom constraint to your resque-web route:
# config/routes.rb
require 'resque/server'
mount Resque::Server.new, :at => "/resque", constraints: ResqueAdmins
# fall back to a default page, such as /login, if the constraint does not return `true`
get '/resque/(*all)', to: redirect(path: '/login')
Check out lib/resque/worker.rb.
When a worker is initialized it's passed a list of queues, which is checks in the order that they're passed.
# file config/initializers/resque.rb
require 'resque/server'
# set a cache time of 1 day in seconds = 86400
module Resque
class Server < Sinatra::Base
set :static_cache_control, [:public, :max_age => 86400]
end
end