diff --git a/Gemfile b/Gemfile index 18af31b..c88093b 100644 --- a/Gemfile +++ b/Gemfile @@ -10,9 +10,10 @@ gem 'devise' gem 'client_side_validations' gem 'twitter' -#gem 'resque', :require => 'resque/server' -gem 'delayed_job_active_record' -gem "delayed_job_web" +gem 'resque', :require => 'resque/server' +# gem 'delayed_job' +# gem 'delayed_job_active_record' +# gem "delayed_job_web" # Gems used only for assets and not required # in production environments by default. diff --git a/Gemfile.lock b/Gemfile.lock index fca9bfd..ecbb189 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -45,17 +45,6 @@ GEM coffee-script-source execjs coffee-script-source (1.2.0) - delayed_job (3.0.0) - activesupport (~> 3.0) - delayed_job_active_record (0.3.1) - activerecord (> 2.1.0) - delayed_job (~> 3.0.0) - delayed_job_web (1.0.3) - activerecord (> 3.0.0) - delayed_job (> 2.0.3) - haml (~> 3.1.3) - rdoc - sinatra (>= 0.9.2) devise (1.5.3) bcrypt-ruby (~> 3.0) orm_adapter (~> 0.0.3) @@ -79,7 +68,6 @@ GEM nokogiri (~> 1.5.0) ruby-hmac formatador (0.2.1) - haml (3.1.4) hike (1.2.1) hirb (0.6.0) i18n (0.6.0) @@ -134,6 +122,14 @@ GEM rake (0.9.2.2) rdoc (3.12) json (~> 1.4) + redis (2.2.2) + redis-namespace (1.0.3) + redis (< 3.0.0) + resque (1.19.0) + multi_json (~> 1.0) + redis-namespace (~> 1.0.2) + sinatra (>= 0.9.2) + vegas (~> 0.1.2) ruby-hmac (0.4.0) sass (3.1.12) sass-rails (3.1.5) @@ -166,6 +162,8 @@ GEM uglifier (1.2.2) execjs (>= 0.3.0) multi_json (>= 1.0.2) + vegas (0.1.8) + rack (>= 1.0.0) warden (1.1.0) rack (>= 1.0) @@ -176,8 +174,6 @@ DEPENDENCIES asset_sync client_side_validations coffee-rails (~> 3.1.1) - delayed_job_active_record - delayed_job_web devise hirb jquery-rails @@ -186,6 +182,7 @@ DEPENDENCIES pg rack-google_analytics rails (= 3.1.1) + resque sass-rails (~> 3.1.4) turn twitter diff --git a/Procfile b/Procfile index d72eee7..e69de29 100644 --- a/Procfile +++ b/Procfile @@ -1 +0,0 @@ -worker: bundle exec rake jobs:work diff --git a/app/models/user.rb b/app/models/user.rb index 607f1d8..d0613cb 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -25,7 +25,8 @@ def to_param private def send_sign_up_notification - UserMailer.welcome_email(self.fullname, self.email).deliver + Resque.enqueue(WelcomeEmailWorker, self.id) + # UserMailer.welcome_email(self.fullname, self.email).deliver # UserMailer.delay(queue: "welcome_email", priority: -1).welcome_email(self.fullname, self.email) end end diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb index 26e05d9..68a92d8 100644 --- a/app/views/users/index.html.erb +++ b/app/views/users/index.html.erb @@ -11,6 +11,7 @@
Habits - <%= user.habits.count %> Tasks - <%= user.tasks.count %> diff --git a/app/workers/welcome_email_worker.rb b/app/workers/welcome_email_worker.rb new file mode 100644 index 0000000..a6f19a4 --- /dev/null +++ b/app/workers/welcome_email_worker.rb @@ -0,0 +1,12 @@ +class WelcomeEmailWorker + + def self.queue + :welcome_email_queue + end + + + def self.perform(user_id) + user = User.find(user_id) + UserMailer.welcome_email(user.fullname, user.email).deliver + end +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 062f5b8..6ecf728 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -85,7 +85,7 @@ end constraints resque_constraint do - match "/delayed_job" => DelayedJobWeb, :anchor => false + mount Resque::Server, :at => "/resque" end # See how all your routes lay out with "rake routes" diff --git a/lib/heroku_resque_auto_scale.rb b/lib/heroku_resque_auto_scale.rb new file mode 100644 index 0000000..f5165f4 --- /dev/null +++ b/lib/heroku_resque_auto_scale.rb @@ -0,0 +1,124 @@ +require 'heroku' + +# Scale workers on Heroku automatically as your Resque queue grows. +# Mixin the +Scaling+ module into your models to get the behavior. +# +# class MyModel < ActiveRecord::Base +# extend HerokuAutoScaler::AutoScaling +# end +# +# And configure in an initializer +config/initializers/heroku_workers.rb+: +# +# HerokuAutoScaler.configure do +# process_type :nowaitworker +# scale_by {|pending| } +# end +# +# The default process type is +worker+. +# The default scaling is non-linear: +# * 1 job => 1 worker +# * 15 jobs => 2 workers +# * 25 jobs => 3 workers +# * 40 jobs => 4 workers +# * 60+ jobs => 5 workers +module HerokuResqueAutoScale + module AutoScaling + def after_perform_scale_down(*args) + HerokuAutoScaler.scale_down! + end + + def after_enqueue_scale_up(*args) + HerokuAutoScaler.scale_up! + end + + def on_failure(e, *args) + Rails.logger.info("Resque Exception for [#{self.to_s}, #{args.join(', ')}] : #{e.to_s}") + HerokuAutoScaler.scale_down! + end + end + + extend self + + def clear_resque + Resque::Worker.all.each {|w| w.unregister_worker} + end + + def configure(&block) + instance_eval(&block) if block_given? + end + + def process_type(type = nil) + @process_type ||= type || :worker + end + + def scale_by(&block) + self.scaling_block = block + end + + def scale_down! + Rails.logger.info "Scale down j:#{job_count} w:#{resque_workers}" + self.heroku_workers = 0 if job_count == 0 && resque_workers == 1 + end + + def scale_up! + pending = job_count + self.heroku_workers = workers_for(pending) if pending > 0 + end + + private + + attr_accessor :scaling_block + + def heroku + if ENV['HEROKU_USER'] && ENV['HEROKU_PASSWORD'] && ENV['HEROKU_APP'] + @heroku ||= Heroku::Client.new(ENV['HEROKU_USER'], ENV['HEROKU_PASSWORD']) + else + false + end + end + + def heroku_workers=(qty) + heroku.ps_scale(ENV['HEROKU_APP'], type: process_type, qty: qty) if heroku + end + + def job_count + Resque.info[:pending] + end + + def resque_workers + Resque.info[:working] + end + + def workers_for(pending_jobs) + if scaling_block + scaling_block.call(pending_jobs) + else + [ + { :workers => 1, # This many workers + :job_count => 1 # For this many jobs or more, until the next level + }, + { :workers => 2, + :job_count => 15 + } + # , + # { :workers => 3, + # :job_count => 25 + # }, + # { :workers => 4, + # :job_count => 40 + # }, + # { :workers => 5, + # :job_count => 60 + # } + ].reverse_each do |scale_info| + # Run backwards so it gets set to the highest value first + # Otherwise if there were 70 jobs, it would get set to 1, then 2, then 3, etc + + # If we have a job count greater than or equal to the job limit for this scale info + if pending_jobs >= scale_info[:job_count] + return scale_info[:workers] + end + end + end + end +end \ No newline at end of file diff --git a/lib/tasks/resque.rake b/lib/tasks/resque.rake new file mode 100644 index 0000000..1e4d1bd --- /dev/null +++ b/lib/tasks/resque.rake @@ -0,0 +1,13 @@ +# require "resque/tasks" +# +# task "resque:setup" => :environment + + +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" \ No newline at end of file