cron_swanson 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f5b92fde06c654c2a37b0162a87e0d1701db2d24f28ae707bbfa174d168d73aa
4
- data.tar.gz: 33d169cfefdb9e1ab75aca3b93f2aedfc2f6c0d6634df1f9a536115b5a964bc9
3
+ metadata.gz: d117286d60628186a24607e387fb3b51eb4b915d8e75a96d92ebfce8ea51a9ed
4
+ data.tar.gz: 7d8fb576c1aead5cbe16c2ccd81f1acda7f96149fb725bd780359a4ba8d2360c
5
5
  SHA512:
6
- metadata.gz: abd309004421dc9cf12886a4e9df6a58717ab51dc74c2cee0ab4fbdbbb4cb4248b462d4d684f6113a0103a8999559eac2cb51580467c6c5ed18b9ac14d73a1b6
7
- data.tar.gz: af381bd1b0054755f8a08248962f546db9ce82ea0706657ace6f47fc5c9aa0425266de8295ee39bfe523bfc2b78e3d3243aa94c1eb8a49edd40ac355f7296557
6
+ metadata.gz: 99a782ff24a871fe8f5ea77f5a4e26c06b0af27519f03873dd62d4e2a5e9a2cd7da478230d3283fcb6b9af28ae03b69d7c3ea64f650683bba7d5f6786017abed
7
+ data.tar.gz: e054da7a55fd73c7a0f8c00e4912f13572467840984b45cb7a1d3041a4c13efdbc9ab965fd13748f26a16eea94afcdad86dba227cf1e2c487d52b97dacd199c8
data/.rspec CHANGED
@@ -1 +1 @@
1
- --require spec_helper
1
+ --require spec_helper --format d
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.4
4
+ - 2.5
5
+ - 2.6
6
+ script:
7
+ - bundle exec rake spec
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0 : "Under my utelage, you will grow from boys to men." : November 3, 2019
4
+
5
+ Improvements in whenever integration.
6
+
7
+ * Jobs are scheduled based on their contents, not their source location.
8
+ * Added support for `roles`.
9
+
10
+ ## 0.1.0 : "I'm not interested in caring about people." : November 1, 2019
11
+
12
+ Initial release
data/README.md CHANGED
@@ -1,8 +1,18 @@
1
1
  # CronSwanson
2
2
 
3
- CronSwanson can help if you have many systems running the same cron job, but you
4
- don't want them all to start at exactly the same time. (To prevent daily load
5
- spikes at midnight, as every single app starts its maintenance cron jobs.)
3
+ `CronSwanson` helps schedule cron jobs.
4
+
5
+ ![Never half-ass two things.](whole-ass.jpg)
6
+
7
+ If you've ever had load spikes when many applications all starting the same
8
+ cron job at the same time, `CronSwanson` can help you.
9
+
10
+ The library generates crontab schedule strings which are consistent (they aren't
11
+ random) but which are fuzzed/shifted depending on some input.
12
+
13
+ ## Build Status
14
+
15
+ [![Build Status](https://travis-ci.org/alexdean/cron_swanson.svg?branch=master)](https://travis-ci.org/alexdean/cron_swanson)
6
16
 
7
17
  ## Installation
8
18
 
@@ -32,6 +42,17 @@ CronSwanson.schedule 'whiskey'
32
42
  #=> "33 18 * * *"
33
43
  ```
34
44
 
45
+ **To keep two applications running the same job from executing at once**, make the
46
+ application name part of the schedule key.
47
+
48
+ ```ruby
49
+ CronSwanson.schedule 'application-a whiskey'
50
+ #=> "4 19 * * *"
51
+
52
+ CronSwanson.schedule 'application-b whiskey'
53
+ #=> "11 7 * * *"
54
+ ```
55
+
35
56
  An `interval` (in seconds) can be supplied if you want a job to be run more than
36
57
  once/day. This `interval` must be a factor of 24 hours.
37
58
 
@@ -40,14 +61,27 @@ CronSwanson.schedule 'bacon', interval: 60 * 60 * 4
40
61
  #=> "26 2,6,10,14,18,22 * * *"
41
62
  ```
42
63
 
64
+ You can also use `ActiveSupport::Duration` instances.
65
+
66
+ ```ruby
67
+ CronSwanson.schedule 'bacon', interval: 4.hours
68
+ #=> "26 2,6,10,14,18,22 * * *"
69
+ ```
70
+
43
71
  ### Whenever Integration
44
72
 
45
73
  `CronSwanson` is built to integrate with the fantastic [whenever](https://github.com/javan/whenever) gem.
46
74
 
75
+ `CronSwanson::Whenever.add` will calculate a run time for jobs by hashing the text
76
+ of the job definitions in the given block.
77
+
78
+ **NOTE**: This means that if you change the jobs in the block, you will also change the schedule time
79
+ for these jobs.
80
+
47
81
  #### Daily
48
82
 
49
83
  ```ruby
50
- # in the config/schedule.rb file
84
+ # in config/schedule.rb
51
85
  CronSwanson::Whenever.add(self) do
52
86
  rake 'sample:job'
53
87
  end
@@ -59,7 +93,7 @@ determined by `CronSwanson`.
59
93
  #### Multiple times/day
60
94
 
61
95
  ```ruby
62
- # in the config/schedule.rb file
96
+ # in config/schedule.rb
63
97
 
64
98
  # with ActiveSupport
65
99
  CronSwanson::Whenever.add(self, interval: 4.hours) do
@@ -74,7 +108,7 @@ end
74
108
 
75
109
  #### job types
76
110
 
77
- The block is evaluated by `whenever`, so any custom job types will work.
111
+ Any custom job types which have been defined will work.
78
112
 
79
113
  ```ruby
80
114
  # in config/schedule.rb
@@ -85,15 +119,21 @@ CronSwanson::Whenever.add(self) do
85
119
  end
86
120
  ```
87
121
 
88
- #### Limitation
122
+ #### roles
89
123
 
90
- The whenever integration code currently derives a scheduled time from the source
91
- location of the `add` call. This means that moving the `.add` invocation to
92
- a different line in schedule.rb will cause it to be run at a different time.
124
+ Roles are supported. See the [whenever documentation](https://github.com/javan/whenever#capistrano-roles)
125
+ for more information on this.
93
126
 
94
- This limitation exists because I (currently) don't know of a way to inspect
95
- the contents of a block at runtime. If a way to do this can be found, I
96
- would prefer to calculate the time based on the block's contents.
127
+ ```ruby
128
+ CronSwanson::Whenever.add(self) do
129
+ rake 'will_run_on_all_roles'
130
+ end
131
+
132
+ # will only be added to servers with the :restricted role
133
+ CronSwanson::Whenever.add(self, roles: [:restricted]) do
134
+ rake 'restricted_only'
135
+ end
136
+ ```
97
137
 
98
138
  ## Development
99
139
 
data/Rakefile CHANGED
@@ -1,2 +1,7 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ desc 'Run all specs in spec directory (excluding plugin specs)'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
2
7
  task default: :spec
@@ -15,7 +15,7 @@ module CronSwanson
15
15
  # offset within a time period
16
16
  #
17
17
  # if the interval is 6 hours, the returned offset will be some number of seconds
18
- # from 0 to 6 hours.
18
+ # between 0 and 60 * 60 * 6 seconds (6 hours).
19
19
  #
20
20
  # @param [String] job_identifier
21
21
  # if nil, method will determine this on its own
@@ -27,7 +27,7 @@ module CronSwanson
27
27
  # largest possible hex sha256 value
28
28
  max_sha256_value = (16**64).to_f
29
29
 
30
- # what % of the max sha256 is the current app?
30
+ # what % of the max sha256 is the job_identifier?
31
31
  sha_pct_of_max_sha256 = sha.to_i(16) / max_sha256_value
32
32
 
33
33
  # apply that same % to the desired interval to get an offset
@@ -49,8 +49,6 @@ module CronSwanson
49
49
  # figure out how many times job will happen in a day
50
50
  runs_per_day = SECONDS_PER_DAY / interval
51
51
 
52
- # raise if runs_per_day has a decimal component.
53
-
54
52
  run_at = Time.at(offset(job_identifier, interval: interval)).utc
55
53
 
56
54
  hours = []
@@ -1,3 +1,3 @@
1
1
  module CronSwanson
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,6 +1,6 @@
1
1
  module CronSwanson
2
2
  # integration for the whenever gem: https://github.com/javan/whenever
3
- module Whenever
3
+ class Whenever
4
4
  # CronSwanson integration for whenever
5
5
  #
6
6
  # The given block can use any job types understood by your whenever configuration.
@@ -15,13 +15,13 @@ module CronSwanson
15
15
  # would prefer to calculate the time based on the block's contents.
16
16
  #
17
17
  # @example run a job once/day
18
- # # in the config/schedule.rb file
18
+ # # in config/schedule.rb
19
19
  # CronSwanson::Whenever.add(self) do
20
20
  # rake 'job'
21
21
  # end
22
22
  #
23
- # @example run a job four times daily
24
- # # in the config/schedule.rb file
23
+ # @example schedule a job to four times daily
24
+ # # in config/schedule.rb
25
25
  #
26
26
  # # with ActiveSupport
27
27
  # CronSwanson::Whenever.add(self, interval: 4.hours) do
@@ -33,19 +33,61 @@ module CronSwanson
33
33
  # rake 'job'
34
34
  # end
35
35
  #
36
+ # @example run a job only on servers with a given role
37
+ # # in config/schedule.rb
38
+ # CronSwanson::Whenever.add(self, roles: [:app]) do
39
+ # rake 'job'
40
+ # end
41
+ #
36
42
  # @param [Whenever::JobList] whenever_job_list For code in `config/schedule.rb`
37
43
  # this can be referred to as `self`.
38
- # @param [Integer] interval how many seconds do you want between runs of this job
39
- def self.add(whenever_job_list, interval: CronSwanson.default_interval, &block)
44
+ # @param [Integer, ActiveSupport::Duration] interval how many seconds do you want between runs
45
+ # of this job
46
+ # @param [Array<Symbol>] roles capistrano roles that jobs in this block should be deployed to
47
+ def self.add(whenever_job_list, interval: CronSwanson.default_interval, roles: [], &block)
48
+ @whenever_jobs = []
49
+ @whenever_job_list = whenever_job_list
50
+
40
51
  if !whenever_job_list.is_a?(::Whenever::JobList)
41
52
  raise ArgumentError, "supply a Whenever::JobList. (In schedule.rb code, use `self`.)"
42
53
  end
43
54
 
44
55
  raise ArgumentError, "provide a block containing jobs to schedule." if !block_given?
45
56
 
46
- # TODO: ideally we'd hash the contents of the block, not the location it was defined at
47
- schedule = CronSwanson.schedule(block.source_location, interval: interval)
48
- whenever_job_list.every(schedule, &Proc.new)
57
+ # execute the block in the context of CronSwanson::Whenever (rather than in the context
58
+ # of the Whenever::JobList where it will be invoked) so that we can intercept
59
+ # calls to `rake` and similar (via method_missing below).
60
+ instance_eval(&block)
61
+
62
+ # make a schedule based on the contents of the jobs which were defined in the block
63
+ schedule_seed = @whenever_jobs.map do |job_config|
64
+ m, args, _block = *job_config
65
+ "#{m} #{args.join}"
66
+ end
67
+ schedule = CronSwanson.schedule(schedule_seed, interval: interval)
68
+
69
+ # now that we know when to schedule the jobs, actually pass the block to Whenever
70
+ if roles.size > 0
71
+ whenever_job_list.every(schedule, roles: roles, &Proc.new)
72
+ else
73
+ whenever_job_list.every(schedule, &Proc.new)
74
+ end
75
+
76
+ @whenever_job_list = nil
77
+ end
78
+
79
+ # during .add, we accumulate calls to whenever job types
80
+ # this allows us to make a schedule hash from the actual jobs which are defined.
81
+ def self.method_missing(m, *args, &block)
82
+ if @whenever_job_list.nil? || @whenever_jobs.nil?
83
+ raise "#{self.name}.method_missing invoked outside of #{self.name}.add"
84
+ end
85
+
86
+ if @whenever_job_list.respond_to?(m)
87
+ @whenever_jobs << [m, args, block]
88
+ else
89
+ raise "#{m} is not defined. Call `job_type` to resolve this."
90
+ end
49
91
  end
50
92
  end
51
93
  end
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cron_swanson
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Dean
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-01 00:00:00.000000000 Z
11
+ date: 2019-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -49,6 +49,8 @@ files:
49
49
  - ".rspec"
50
50
  - ".rubocop.yml"
51
51
  - ".ruby-version"
52
+ - ".travis.yml"
53
+ - CHANGELOG.md
52
54
  - Gemfile
53
55
  - Guardfile
54
56
  - README.md
@@ -62,6 +64,7 @@ files:
62
64
  - lib/cron_swanson.rb
63
65
  - lib/cron_swanson/version.rb
64
66
  - lib/cron_swanson/whenever.rb
67
+ - whole-ass.jpg
65
68
  homepage: https://github.com/alexdean/cron_swanson
66
69
  licenses: []
67
70
  metadata: {}