Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,3 @@ Style/DoubleNegation:
Enabled: false
Metrics/PerceivedComplexity:
Enabled: false
Metrics/ClassLength:
Max: 110
25 changes: 12 additions & 13 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,45 +1,44 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2016-06-26 12:36:38 -0400 using RuboCop version 0.40.0.
# on 2021-07-10 20:06:41 +0000 using RuboCop version 0.40.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.

# Offense count: 1
# Configuration parameters: AllowSafeAssignment.
Lint/AssignmentInCondition:
Exclude:
- 'lib/resque/scheduler/env.rb'

# Offense count: 2
Lint/UselessAccessModifier:
Exclude:
- 'lib/resque/scheduler.rb'

# Offense count: 17
# Offense count: 18
Metrics/AbcSize:
Max: 36
Max: 41

# Offense count: 3
# Offense count: 1
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 112

# Offense count: 5
Metrics/CyclomaticComplexity:
Max: 12

# Offense count: 6
# Offense count: 11
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
# URISchemes: http, https
Metrics/LineLength:
Max: 96

# Offense count: 20
# Offense count: 23
# Configuration parameters: CountComments.
Metrics/MethodLength:
Max: 34

# Offense count: 2
# Configuration parameters: CountComments.
Metrics/ModuleLength:
Max: 331
Max: 350

# Offense count: 1
Style/CaseEquality:
Expand Down
3 changes: 2 additions & 1 deletion AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Resque Scheduler authors
- Aaron Suggs
- Alexander Simonov
- Andrea Campolonghi
- Andrea Lorenzetti
- Ben VandenBos
- Bernerd Schaefer
- Bogdan Gusiev
Expand Down Expand Up @@ -86,4 +87,4 @@ Resque Scheduler authors
- malomalo
- sawanoboly
- serek
- iloveitaly
- iloveitaly
45 changes: 44 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ Resque.schedule = YAML.load_file('your_resque_schedule.yml')

If a static schedule is not set `resque-scheduler` will issue a "Schedule empty!" warning on
startup, but despite that warning setting a static schedule is totally optional. It is possible
to use only dynamic schedules (see below).
to use only dynamic schedules or auto load (see below).

The schedule file is a list of Resque job classes with arguments and a
schedule frequency (in crontab syntax). The schedule is just a hash, but
Expand Down Expand Up @@ -445,6 +445,49 @@ config[:every] = '1d'
Resque.set_schedule(name, config)
```

#### Auto load

With auto load you specify a path from which jobs will be loaded and scheduled without the needs of static scheduling or dynamic scheduling.

Auto load are not enabled by default. To be able to auto load set schedules, you must pass the following to resque-scheduler initialization (see Installation above for a more complete example):

```ruby
Resque::Scheduler.auto_load = 'path/to/*_job.rb'
```

Auto load enables a job to declare it's scheduling. In order to do that file must follow `snake_case` convention for filename and `CamelCase` for class name. It also must include `Resque::Scheduler::Job` and declares it's schedule:

```ruby
resque_schedule cron: '*/2 * * * *'
```

All options available:

```ruby
resque_schedule(
cron: '* */3 * * *', # use cron or every option, don't use both
every: '3d', # use every or cron option, don't use both
args: 'Custom arg',
description: 'Nice description'
)
```

Job's example:

```ruby
# my_great_job.rb
require 'resque/scheduler/job'

class MyGreatJob
include Resque::Scheduler::Job

@queue = :default

resque_schedule cron: '*/2 * * * *', args: 'args', description: 'description'
end

```

#### Time zones

If you use the cron syntax, by default it is interpreted in the server time zone.
Expand Down
5 changes: 5 additions & 0 deletions lib/resque/scheduler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ def load_schedule!
Resque.schedule.each do |name, config|
load_schedule_job(name, config)
end

Dir[auto_load.to_s].each do |file|
require File.absolute_path(file)
end

Resque.redis.del(:schedules_changed) if am_master && dynamic
procline 'Schedules Loaded'
end
Expand Down
5 changes: 5 additions & 0 deletions lib/resque/scheduler/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module Scheduler
app_name: 'APP_NAME',
background: 'BACKGROUND',
dynamic: 'DYNAMIC_SCHEDULE',
auto_load: 'AUTO_LOAD',
env: 'RAILS_ENV',
initializer_path: 'INITIALIZER_PATH',
logfile: 'LOGFILE',
Expand All @@ -31,6 +32,10 @@ class Cli
'Application name for procline'],
callback: ->(options) { ->(n) { options[:app_name] = n } }
},
{
args: ['-A', '--auto-load [AUTO_LOAD]', 'Enable jobs auto load'],
callback: ->(options) { ->(a) { options[:auto_load] = a } }
},
{
args: ['-B', '--background', 'Run in the background [BACKGROUND]'],
callback: ->(options) { ->(b) { options[:background] = b } }
Expand Down
7 changes: 7 additions & 0 deletions lib/resque/scheduler/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ def dynamic
@dynamic ||= to_bool(environment['DYNAMIC_SCHEDULE'])
end

# If set, will try to automatically load those jobs
attr_writer :auto_load

def auto_load
@auto_load ||= !!ENV['AUTO_LOAD']
end

# If set, will append the app name to procline
attr_writer :app_name

Expand Down
2 changes: 2 additions & 0 deletions lib/resque/scheduler/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ def setup_scheduler_configuration

c.dynamic = !!options[:dynamic] if options.key?(:dynamic)

c.auto_load = options[:auto_load] if options.key?(:auto_load)

c.env = options[:env] if options.key?(:env)

c.logfile = options[:logfile] if options.key?(:logfile)
Expand Down
27 changes: 27 additions & 0 deletions lib/resque/scheduler/job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# vim:fileencoding=utf-8

module Resque
module Scheduler
module Job
class << self
def included(base)
base.extend ClassMethods
end
end

module ClassMethods
def resque_schedule(cron: nil, every: nil, args: nil, description: nil)
Resque::Scheduler.load_schedule_job(
name,
'class' => name,
'cron' => cron,
'every' => every,
'queue' => @queue,
'args' => args,
'description' => description
)
end
end
end
end
end
11 changes: 9 additions & 2 deletions lib/resque/scheduler/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ class Util
# Scheduler. refer to:
# https://github.com/resque/resque-scheduler/pull/273

CLASSIFY_DELIMETERS = %w(- _).freeze

def self.constantize(camel_cased_word)
camel_cased_word = camel_cased_word.to_s

if camel_cased_word.include?('-')
unless (camel_cased_word.chars & CLASSIFY_DELIMETERS).empty?
camel_cased_word = classify(camel_cased_word)
end

Expand All @@ -32,7 +34,12 @@ def self.constantize(camel_cased_word)
end

def self.classify(dashed_word)
dashed_word.split('-').map(&:capitalize).join
CLASSIFY_DELIMETERS.each do |delimiter|
dashed_word = dashed_word.split(delimiter)
.map { |w| w[0].capitalize + w[1..-1] }
.join
end
dashed_word
end
end
end
Expand Down
16 changes: 16 additions & 0 deletions test/cli_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ def new_cli(argv = [], env = {})
assert_equal(nil, new_cli.send(:options)[:dynamic])
end

test 'defaults to nil auto_load' do
assert_equal(nil, new_cli.send(:options)[:auto_load])
end

test 'initializes env from the env' do
cli = new_cli([], 'RAILS_ENV' => 'flurb')
assert_equal('flurb', cli.send(:options)[:env])
Expand Down Expand Up @@ -224,6 +228,18 @@ def new_cli(argv = [], env = {})
assert_equal('flimsy', cli.send(:options)[:app_name])
end

test 'accepts auto_load via -A' do
cli = new_cli(%w(-A /some/path_*_job.rb))
cli.parse_options
assert_equal('/some/path_*_job.rb', cli.send(:options)[:auto_load])
end

test 'accepts auto_load via --auto-load' do
cli = new_cli(%w(--auto-load /some/path_*_job.rb))
cli.parse_options
assert_equal('/some/path_*_job.rb', cli.send(:options)[:auto_load])
end

test 'runs Resque::Scheduler' do
Resque::Scheduler.expects(:run)
Resque::Scheduler::Cli.run!([], {})
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/error_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# vim:fileencoding=utf-8

require 'resque/scheduler/job'

class ErrorJob
include Resque::Scheduler::Job
end
11 changes: 11 additions & 0 deletions test/fixtures/valid_cron_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# vim:fileencoding=utf-8

require 'resque/scheduler/job'

class ValidCronJob
include Resque::Scheduler::Job

@queue = :default

resque_schedule cron: '*/2 * * * *', args: 'args', description: 'description'
end
11 changes: 11 additions & 0 deletions test/fixtures/valid_every_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# vim:fileencoding=utf-8

require 'resque/scheduler/job'

class ValidEveryJob
include Resque::Scheduler::Job

@queue = :default

resque_schedule every: '1d', args: 'args', description: 'description'
end
29 changes: 29 additions & 0 deletions test/scheduler_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
c.quiet = true
c.env = nil
c.app_name = nil
c.auto_load = nil
end
Resque.schedule.clear
Resque.data_store.redis.flushall
Resque::Scheduler.clear_schedule!
Resque::Scheduler.send(:instance_variable_set, :@scheduled_jobs, {})
Expand Down Expand Up @@ -104,6 +106,33 @@
assert Resque::Scheduler.scheduled_jobs.include?('some_ivar_job2')
end

test 'can load jobs with auto_load' do
Resque::Scheduler.auto_load = 'test/fixtures/valid*job.rb'

Resque::Scheduler.reload_schedule!

assert_equal(2, Resque::Scheduler.rufus_scheduler.jobs.size)
assert_equal(2, Resque::Scheduler.scheduled_jobs.size)
%w(ValidCronJob ValidEveryJob).each do |job_name|
assert Resque::Scheduler.scheduled_jobs.keys.include?(job_name)
end

cron_job = Resque::Scheduler.scheduled_jobs['ValidCronJob']
assert_equal('*/2 * * * *', cron_job.original)

every_job = Resque::Scheduler.scheduled_jobs['ValidEveryJob']
assert_equal('1d', every_job.original)
end

test 'do not load error job with auto_load' do
Resque::Scheduler.auto_load = 'test/fixtures/error_job.rb'

Resque::Scheduler.reload_schedule!

assert_equal(0, Resque::Scheduler.rufus_scheduler.jobs.size)
assert_equal(0, Resque::Scheduler.scheduled_jobs.size)
end

test 'load_schedule_job loads a schedule' do
Resque::Scheduler.load_schedule_job(
'some_ivar_job',
Expand Down
4 changes: 4 additions & 0 deletions test/util_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ module ReSchedulIzer; end
test 'constantizing with a dash' do
assert util.constantize('re-schedul-izer') == ReSchedulIzer
end

test 'constantizing with an underscore' do
assert util.constantize('re_schedul_izer') == ReSchedulIzer
end
end