Skip to content

Commit

Permalink
* added auto_load option to allow jobs to declare theirs schedule
Browse files Browse the repository at this point in the history
  • Loading branch information
and9000 committed Jul 11, 2021
1 parent 41dafe8 commit c3ce50f
Show file tree
Hide file tree
Showing 17 changed files with 254 additions and 18 deletions.
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
1 change: 1 addition & 0 deletions 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
46 changes: 45 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,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 @@ -405,6 +405,50 @@ 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
cron '*/2 * * * *'
queue 'default'
```

All options available:

```ruby
cron '* */3 * * *' # use cron or every option, don't use both
every '3d' # use every or cron option, don't use both
queue 'default'
args 'custom arg'
description 'Nice description'
```

Job's example:

```ruby
# my_great_job.rb
require 'resque/scheduler/job'
class MyGreatJob
include Resque::Scheduler::Job
cron '*/2 * * * *'
queue 'default'
args 'args'
description 'description'
end
```

#### Time zones

Note that if you use the cron syntax, this will be interpreted as in the server time zone
Expand Down
20 changes: 20 additions & 0 deletions lib/resque/scheduler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,26 @@ 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)
name = File.basename(file, '.rb')
begin
klass = Resque::Scheduler::Util.constantize(name)
rescue NameError
log! "Can't load file #{file}"
end
load_schedule_job(
name,
'class' => klass.name,
'cron' => klass.respond_to?(:cron) ? klass.cron : nil,
'every' => klass.respond_to?(:every) ? klass.every : nil,
'queue' => klass.respond_to?(:queue) ? klass.queue : nil,
'args' => klass.respond_to?(:args) ? klass.args : nil,
'description' => klass.respond_to?(:description) ? klass.description : nil
) if klass
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 @@ -53,6 +53,13 @@ def dynamic
@dynamic ||= !!ENV['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 @@ -64,6 +64,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
40 changes: 40 additions & 0 deletions lib/resque/scheduler/job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# vim:fileencoding=utf-8

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

module ClassMethods
def cron(value = nil)
return @cron ||= nil if value.nil?
@cron = value
end

def every(value = nil)
return @every ||= nil if value.nil?
@every = value
end

def queue(value = nil)
return @queue ||= nil if value.nil?
@queue = value
end

def args(value = nil)
return @args ||= nil if value.nil?
@args = value
end

def description(value = nil)
return @description ||= nil if value.nil?
@description = value
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
12 changes: 12 additions & 0 deletions test/fixtures/valid_cron_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# vim:fileencoding=utf-8

require 'resque/scheduler/job'

class ValidCronJob
include Resque::Scheduler::Job

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

require 'resque/scheduler/job'

class ValidEveryJob
include Resque::Scheduler::Job

every '1d'
queue 'default'
args 'args'
description 'description'
end
33 changes: 33 additions & 0 deletions test/job_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# vim:fileencoding=utf-8

require 'resque/scheduler/job'

context 'Job' do
test 'has nil default parameters' do
class EmptyJob
include Resque::Scheduler::Job
end

%i(cron every queue args description).each do |p|
assert_nil EmptyJob.send(p)
end
end

test 'saves values' do
class JobWithValues
include Resque::Scheduler::Job

cron '* */3 * * *'
every '3d'
queue 'default'
args 'some arg'
description 'nice description'
end

assert_equal '* */3 * * *', JobWithValues.cron
assert_equal '3d', JobWithValues.every
assert_equal 'default', JobWithValues.queue
assert_equal 'some arg', JobWithValues.args
assert_equal 'nice description', JobWithValues.description
end
end
Loading

0 comments on commit c3ce50f

Please sign in to comment.