Skip to content

Commit

Permalink
add scheduler, retry, multy-job-forks
Browse files Browse the repository at this point in the history
  • Loading branch information
bibendi committed Nov 10, 2014
1 parent 217ab60 commit 78ffdd9
Show file tree
Hide file tree
Showing 15 changed files with 257 additions and 32 deletions.
Empty file added CHANGELOG
Empty file.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
source 'http://apress:[email protected]'
source 'https://rubygems.org'

# Specify your gem's dependencies in resque-integration.gemspec
Expand Down
15 changes: 15 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
RAILS_ENV = test
BUNDLE = RAILS_ENV=${RAILS_ENV} bundle
BUNDLE_OPTIONS = -j 2
RSPEC = rspec

all: test

test: bundler/install
${BUNDLE} exec ${RSPEC} spec 2>&1

bundler/install:
if ! gem list bundler -i > /dev/null; then \
gem install bundler; \
fi
${BUNDLE} install ${BUNDLE_OPTIONS}
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# Resque::Integration

<a href="http://dolly.railsc.ru/projects/47/builds/latest/?ref=master"><img src="http://dolly.railsc.ru/badges/abak-press/resque-integration/master" height=18 /></a>

Интеграция Resque в Rails-приложения с поддержкой следующих плагинов:
* [resque-progress](https://github.com/idris/resque-progress)
* [resque-lock](https://github.com/defunkt/resque-lock)
* [resque-multi-job-forks](https://github.com/stulentsev/resque-multi-job-forks)
* [resque-failed-job-mailer](https://github.com/anandagrawal84/resque_failed_job_mailer)
* [resque-scheduler](https://github.com/resque/resque-scheduler)
* [resque-retry](https://github.com/lantins/resque-retry)

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

Expand Down Expand Up @@ -208,3 +212,46 @@ meta = ResqueJobTest.enqueue(id=2)
```ruby
Resque.enqueue(ImageProcessingJob, id=2)
```

## Resque Scheduler

Расписание для cron-like заданий должно храниться здесь `config/resque_schedule.yml`

## Resque Retry

В силу несовместимостей почти всех плагинов с resque-meta (unique основан на нём) - объявить задание перезапускаемым
в случае ошибки нужно ДО `unique`

```ruby
class ResqueJobTest
include Resque::Integration

retrys delay: 10, limit: 2
unique
end
```

## Resque Multi Job Forks

```yaml
workers:
'high':
count: 1
jobs_per_fork: 10
```
## Gem Releasing
1. должен быть настроен git remote upstream и должны быть права на push
1. git checkout master
2. git pull upstream master
3. правим версию гема в файле VERSION в корне гема. (читаем правила версионирования http://semver.org/)
4. bundle exec rake release
## Contributing
1. Fork it ( https://github.com/abak-press/resque-integration/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request
8 changes: 7 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
require "bundler/gem_tasks"
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end

require 'apress/gems/rake_tasks'
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

25 changes: 24 additions & 1 deletion lib/resque/integration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
require 'resque/integration/hooks'
require 'resque/integration/engine'

require 'resque/scheduler'
require 'resque/scheduler/tasks'

require 'resque-retry'

require 'active_support/core_ext/module/attribute_accessors'

module Resque
Expand Down Expand Up @@ -79,6 +84,24 @@ def continuous
def unique?
false
end

# extend resque-retry
#
# options - Hash
# :limit - Integer (default: 2)
# :delay - Integer (default: 60)
#
# Returns nothing
def retrys(options = {})
if unique?
raise '`retrys` should be declared higher in code than `unique`'
end

extend Resque::Plugins::Retry

@retry_limit = options.fetch(:limit, 2)
@retry_delay = options.fetch(:delay, 60)
end
end
end # module Integration
end # module Resque
end # module Resque
37 changes: 34 additions & 3 deletions lib/resque/integration/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ def verbosity
(self['resque.verbosity'] || 0).to_i
end

# Returns Resque log level
def log_level
(self['resque.log_level'] || 1).to_i
end

# Returns path to resque log file
def log_file
self['resque.log_file'] || ::Rails.root.join('log/resque.log').to_s
Expand All @@ -136,6 +141,34 @@ def root
self['resque.root'] || ::Rails.root.to_s
end

# Путь до файла с расписание resque schedule
#
# Returns String
def schedule_file
self['resque.schedule_file'] || ::Rails.root.join('config', 'resque_schedule.yml')
end

# Есть ли расписание у приложения?
#
# Returns boolean
def schedule_exists?
return @schedule_exists if defined?(@schedule_exists)
@schedule_exists = File.exist?(schedule_file)
end

# Используется ли resque scheduler
#
# Returns boolean
def resque_scheduler?
value = self['resque.scheduler'] || true

if value.is_a?(String) && %w(n no false off disabled).include?(value)
value = false
end

value
end

# Returns maximum terminate timeout
def terminate_timeout
workers.map(&:stop_timeout).compact.max.to_i + 10
Expand All @@ -146,8 +179,6 @@ def env
env = self['env'] || {}

env[:INTERVAL] ||= interval
env[:VERBOSE] = '1' if verbosity == 1
env[:VVERBOSE] = '1' if verbosity == 2

Hash[env.map { |k, v| [k, v.to_s] }]
end
Expand Down Expand Up @@ -182,4 +213,4 @@ def [](path)
end
end # class Configuration
end # module Integration
end # module Resque
end # module Resque
16 changes: 14 additions & 2 deletions lib/resque/integration/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ class Engine < Rails::Engine
rake_tasks do
load 'resque/integration/tasks/hooks.rake'
load 'resque/integration/tasks/resque.rake'
load 'resque/integration/tasks/supervisor.rake' # deprecated
end

# Читает конфиг-файлы config/resque.yml и config/resque.local.yml,
Expand All @@ -35,6 +34,19 @@ class Engine < Rails::Engine
end
end

initializer 'resque-integration.logger' do
Resque.logger.level = Resque.config.log_level

case Resque.config.verbosity
when 1
Resque.logger.formatter = Resque::VerboseFormatter.new
when 2
Resque.logger.formatter = Resque::VeryVerboseFormatter.new
else
Resque.logger.formatter = Resque::QuietFormatter.new
end
end

# Конфигурирование плагина resque-failed-job-mailer.
# Данные берутся из конфига (см. выше)
initializer 'resque-integration.failure_notifier' do
Expand All @@ -53,4 +65,4 @@ class Engine < Rails::Engine
end
end
end # class Engine
end # module Resque::Integration
end # module Resque::Integration
46 changes: 45 additions & 1 deletion lib/resque/integration/god.erb
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,48 @@ God.terminate_timeout = <%= terminate_timeout.to_i %>
# END OF WORKER CONFIGURATION
end
<% end %>
<% end %>
<% end %>
<% if resque_scheduler? %>
God.watch do |w|
w.dir = rails_root
w.name = 'resque-scheduler'
w.group = 'resque'
w.interval = 30.seconds
w.env = <%= Resque.config.env.merge(:RAILS_ENV => ::Rails.env, :BUNDLE_GEMFILE => "#{root}/Gemfile").stringify_keys! %>
w.start = "#{bundle} exec rake -f #{rails_root}/Rakefile environment resque:scheduler"
w.log = '<%= log_file %>'
w.stop_signal = 'QUIT'
w.stop_timeout = 60.seconds

# determine the state on startup
w.transition(:init, { true => :up, false => :start }) do |on|
on.condition(:process_running) do |c|
c.running = true
end
end

# determine when process has finished starting
w.transition([:start, :restart], :up) do |on|
on.condition(:process_running) do |c|
c.running = true
c.interval = 5.seconds
end

# failsafe
on.condition(:tries) do |c|
c.times = 5
c.transition = :start
c.interval = 5.seconds
end
end

# start if process is not running
w.transition(:up, :start) do |on|
on.condition(:process_running) do |c|
c.running = false
end
end
# END OF SCHEDULE CONFIGURATION
end
<% end %>
10 changes: 7 additions & 3 deletions lib/resque/integration/tasks/hooks.rake
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,15 @@ namespace :resque do
Resque.before_first_fork { Rails.cache.reset if Rails.cache.respond_to?(:reset) }

# Красиво нарисуем название процесса
Resque.after_fork { |job| $0 = "resque-#{Resque::Version}: Processing #{job.queue}/#{job.payload['class']} since #{Time.now.to_s(:db)}" }
Resque.after_fork do |job|
$0 = "resque-#{Resque::Version}: Processing #{job.queue}/#{job.payload['class']} since #{Time.now.to_s(:db)}"
end

# Support for resque-multi-job-forks
if ENV['JOBS_PER_FORK'] || ENV['MINUTES_PER_FORK']
#require 'resque-multi-job-forks'
require 'resque-multi-job-forks' if ENV['JOBS_PER_FORK'] || ENV['MINUTES_PER_FORK']

if Resque.config.resque_scheduler? && Resque.config.schedule_exists?
Resque.schedule = YAML.load_file(Resque.config.schedule_file)
end
end
end
14 changes: 0 additions & 14 deletions lib/resque/integration/tasks/supervisor.rake

This file was deleted.

16 changes: 14 additions & 2 deletions lib/resque/integration/unique.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
require 'active_support/core_ext/module/aliasing'

require 'resque/plugins/lock'
require 'resque/plugins/progress'
silence_warnings { require 'resque/plugins/progress' } # suppress Resque::Helpers warn

module Resque
module Integration
Expand Down Expand Up @@ -42,6 +42,18 @@ def unique?
true
end

# Метод вызывает resque-scheduler чтобы поставить задание в текущую очередь
def scheduled(queue, klass, *args)
klass.constantize.enqueue(*args)
end

# Метод вызывает resque-retry когда ставить отложенное задание
# здесь мы убираем meta_id из аргументов
def retry_args(*args)
args.shift
args
end

# Get or set proc returning unique arguments
def lock_on(&block)
if block_given?
Expand Down Expand Up @@ -164,4 +176,4 @@ def obj_to_string(obj)
end # module ClassMethods
end # module Unique
end # module Integration
end # module Resque
end # module Resque
10 changes: 6 additions & 4 deletions resque-integration.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,26 @@ Gem::Specification.new do |gem|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
gem.require_paths = %w(lib)

gem.add_runtime_dependency 'resque', '= 1.23.0'
gem.add_runtime_dependency 'resque', '= 1.25.2'
gem.add_runtime_dependency 'railties', '>= 3.0.0'
gem.add_runtime_dependency 'resque-rails', '>= 1.0.1'
gem.add_runtime_dependency 'resque-ensure-connected', '>= 0.2.0' # reconnect after fork
gem.add_runtime_dependency 'resque-lock', '~> 1.1.0'
gem.add_runtime_dependency 'resque-meta', '>= 2.0.0'
gem.add_runtime_dependency 'resque-progress', '~> 1.0.1'
#gem.add_runtime_dependency 'resque-multi-job-forks', '~> 0.3.4'
gem.add_runtime_dependency 'resque-multi-job-forks', '~> 0.4.2'
gem.add_runtime_dependency 'resque-failed-job-mailer', '~> 0.0.3'
gem.add_runtime_dependency 'resque-scheduler', '~> 3.0'
gem.add_runtime_dependency 'resque-retry', '~> 1.3'
gem.add_runtime_dependency 'god', '~> 0.13.4'

gem.add_runtime_dependency 'multi_json'
gem.add_runtime_dependency 'rake'
gem.add_runtime_dependency 'sinatra'

gem.add_development_dependency 'rake'
gem.add_development_dependency 'bundler'
gem.add_development_dependency 'rspec'
gem.add_development_dependency 'rspec', '~> 2.14'
gem.add_development_dependency 'simplecov'
gem.add_development_dependency 'mock_redis'
gem.add_development_dependency 'apress-gems', '>= 0.0.4'
end
Loading

0 comments on commit 78ffdd9

Please sign in to comment.