Class: CronSwanson::Whenever

Inherits:
Object
  • Object
show all
Defined in:
lib/cron_swanson/whenever.rb

Overview

integration for the whenever gem: github.com/javan/whenever

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(whenever_job_list, seed: '') ⇒ Whenever

Returns a new instance of Whenever.



10
11
12
13
14
15
16
17
18
19
# File 'lib/cron_swanson/whenever.rb', line 10

def initialize(whenever_job_list, seed: '')
  if !whenever_job_list.is_a?(::Whenever::JobList)
    raise ArgumentError, "supply a Whenever::JobList. (In schedule.rb code, use `self`.)"
  end

  @whenever_job_list = whenever_job_list
  @seed = seed.to_s
  @in_schedule_method = false
  @whenever_jobs = []
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args, &block) ⇒ Object

during .schedule, we accumulate calls to whenever job types this allows us to make a schedule hash from the actual jobs which are defined.



94
95
96
97
98
99
100
101
102
103
104
# File 'lib/cron_swanson/whenever.rb', line 94

def method_missing(m, *args, &block)
  if !@in_schedule_method
    raise "#{self.class.name}#method_missing invoked outside of #{self.class.name}#schedule"
  end

  if @whenever_job_list.respond_to?(m)
    @whenever_jobs << [m, args, block]
  else
    raise "#{m} is not defined. Call `job_type` to resolve this."
  end
end

Instance Attribute Details

#seedObject (readonly)

a seed string which should be unique per application

causes unique hashes (ie: schedules) to be generated by multiple apps all scheduling the same job.



8
9
10
# File 'lib/cron_swanson/whenever.rb', line 8

def seed
  @seed
end

Instance Method Details

#schedule(interval: CronSwanson.default_interval, roles: [], &block) ⇒ Object

CronSwanson integration for whenever

The given block can use any job types understood by your whenever configuration. See github.com/javan/whenever#define-your-own-job-types.

CronSwanson currently uses the location it is invoked from in schedule.rb to calculate a job time. This means that moving the ‘.schedule` invocation to a different line in schedule.rb will cause it to be run at a different time.

This limitation exists because I (currently) don’t know of a way to inspect the contents of a block at runtime. If a way to do this can be found, I would prefer to calculate the time based on the block’s contents.

Examples:

run a job once/day

# in config/schedule.rb
CronSwanson::Whenever.schedule(self) do
  rake 'job'
end

schedule a job to four times daily

# in config/schedule.rb

# with ActiveSupport
CronSwanson::Whenever.schedule(self, interval: 4.hours) do
  rake 'job'
end

# without ActiveSupport
CronSwanson::Whenever.schedule(self, interval: 60 * 60 * 4) do
  rake 'job'
end

run a job only on servers with a given role

# in config/schedule.rb
CronSwanson::Whenever.schedule(self, roles: [:app]) do
  rake 'job'
end

Parameters:

  • whenever_job_list (Whenever::JobList)

    For code in ‘config/schedule.rb` this can be referred to as `self`.

  • interval (Integer, ActiveSupport::Duration) (defaults to: CronSwanson.default_interval)

    how many seconds do you want between runs of this job

  • roles (Array<Symbol>) (defaults to: [])

    capistrano roles that jobs in this block should be deployed to

Raises:

  • (ArgumentError)


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/cron_swanson/whenever.rb', line 64

def schedule(interval: CronSwanson.default_interval, roles: [], &block)
  @in_schedule_method = true
  @whenever_jobs = []

  raise ArgumentError, "provide a block containing jobs to schedule." if !block_given?

  # execute the block in the context of CronSwanson::Whenever (rather than in the context
  # of the Whenever::JobList where it will be invoked) so that we can intercept
  # calls to `rake` and similar (via method_missing below).
  instance_eval(&block)

  # make a schedule based on the contents of the jobs which were defined in the block
  schedule_seed = @whenever_jobs.map do |job_config|
    m, args, _block = *job_config
    "#{m} #{args.join}"
  end
  schedule = CronSwanson.build_schedule(@seed + schedule_seed.join, interval: interval)

  # now that we know when to schedule the jobs, actually pass the block to Whenever
  if roles.size > 0
    @whenever_job_list.every(schedule, roles: roles, &Proc.new)
  else
    @whenever_job_list.every(schedule, &Proc.new)
  end

  @in_schedule_method = false
end