simple_scheduler 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
  SHA1:
3
- metadata.gz: 8d15cd2b0b48692188a8b470d258e667dae84d08
4
- data.tar.gz: 20eca360c888dbf7e482377f8d78053e988906c5
3
+ metadata.gz: 7f15bb865956e8b2d8b84e65ba2baf7386333a5f
4
+ data.tar.gz: bf3cd7c9bac2b2d9d2085b8d4b4c55000977c98f
5
5
  SHA512:
6
- metadata.gz: 452dae7f622c805289ade38235a8041d9ed23faeb9bd5a1acfa51577570afd07667dbb70d5d099c7630c9ca4fbe04245d80c53655f14464c50369bdb8747a52c
7
- data.tar.gz: f1d49ad79d145d281ce24d4476c752c1d51ae8b37cba98e6e25830c0bc355a2b12e4c3b36a475a25f86a2456e74b0796c237ecae28f0eabd127ebf7d3ec79ac7
6
+ metadata.gz: ca37117e04fcb7c0e4582f702f6262a9051f33c7cfe6f0ee1ce6a80120515128f07ec4a71b3cd5014ce1da5ca1bc424e1b3b86005014bf897c431609b30c3762
7
+ data.tar.gz: df9d6c1ccbeb51d64c6ae5c5bd40bc5305cdeeaa4efb214ce7cf4b2f79cc2565aeffb449009fb2cdbc193ccfcbc32d223a3cdf87167f155d4d969d174d3be9de
data/README.md CHANGED
@@ -37,7 +37,9 @@ $ bundle
37
37
 
38
38
  ## Getting Started
39
39
 
40
- Create a configuration file `config/simple_scheduler.yml`:
40
+ ### Create the Configuration File
41
+
42
+ Create the file `config/simple_scheduler.yml` in your Rails project:
41
43
 
42
44
  ```yml
43
45
  # Global configuration options and their defaults. These can also be set on each task.
@@ -49,11 +51,13 @@ simple_task:
49
51
  class: "SomeActiveJob"
50
52
  every: "2.minutes"
51
53
 
52
- # Runs once every day at 4:00 AM
54
+ # Runs once every day at 4:00 AM. The job will expire after 23 hours, which means the
55
+ # job will not run if 23 hours passes (server downtime) before the job is actually run
53
56
  overnight_task:
54
57
  class: "SomeSidekiqWorker"
55
58
  every: "1.day"
56
59
  at: "4:00"
60
+ expires_after: "23.hours"
57
61
 
58
62
  # Runs once every hour at the half hour
59
63
  half_hour_task:
@@ -69,7 +73,21 @@ weekly_task:
69
73
  tz: "America/Chicago"
70
74
  ```
71
75
 
72
- ### Task options
76
+ ### Set up Heroku Scheduler
77
+
78
+ Add the rake task to Heroku Scheduler and set it to run every 10 minutes:
79
+
80
+ ```
81
+ rake simple_scheduler
82
+ ```
83
+
84
+ It may be useful to point to a specific configuration file in non-production environments:
85
+
86
+ ```
87
+ rake simple_scheduler["config/simple_scheduler.staging.yml"]
88
+ ```
89
+
90
+ ### Task Options
73
91
 
74
92
  #### :class
75
93
 
@@ -81,12 +99,12 @@ on the `perform` method.
81
99
 
82
100
  How frequently the task should be performed as an ActiveSupport duration definition.
83
101
 
84
- ```ruby
85
- 1.day
86
- 5.days
87
- 12.hours
88
- 20.minutes
89
- 1.week
102
+ ```yml
103
+ "1.day"
104
+ "5.days"
105
+ "12.hours"
106
+ "20.minutes"
107
+ "1.week"
90
108
  ```
91
109
 
92
110
  #### :at (optional)
@@ -97,60 +115,67 @@ follow the `every` duration to determine future execution times.
97
115
 
98
116
  Valid string formats/examples:
99
117
 
100
- ```
101
- 18:00
102
- 3:30
103
- **:00
104
- *:30
105
- Sun 2:00
106
- [Sun|Mon|Tue|Wed|Thu|Fri|Sat] 00:00
118
+ ```yml
119
+ "18:00"
120
+ "3:30"
121
+ "**:00"
122
+ "*:30"
123
+ "Sun 2:00"
124
+ "[Sun|Mon|Tue|Wed|Thu|Fri|Sat] 00:00"
107
125
  ```
108
126
 
109
- Add the rake task to Heroku Scheduler and set it to run every 10 minutes:
127
+ #### :expires_after (optional)
110
128
 
111
- ```
112
- rake simple_scheduler
113
- ```
129
+ If your worker process is down for an extended period of time, you may not want jobs
130
+ to execute when the server comes back online. By specifying an `expires_after` value,
131
+ your job will not fire if the time the job actually runs later, by the specified
132
+ duration, than the scheduled run time.
114
133
 
115
- The file `config/simple_scheduler.yml` will be used by default, but it may be
116
- useful to point to another configuration file in non-production environments.
134
+ The string should be in the form of an ActiveSupport duration.
117
135
 
118
- ```
119
- rake simple_scheduler["config/simple_scheduler.staging.yml"]
136
+ ```yml
137
+ "59.minutes"
138
+ "23.hours"
120
139
  ```
121
140
 
122
141
  ## Writing Your Jobs
123
142
 
124
- Your Active Job or Sidekiq Worker must accept the task name and time stamp
125
- as arguments. This is so they can be queued properly and so your job can
126
- use the scheduled time to know when it was supposed to run vs the current time.
143
+ There is no guarantee that the job will run at the exact time given in the
144
+ configuration, so the time the job was scheduled to run will be passed to
145
+ the job. This allows you to handle situations where the current time doesn't
146
+ match the time it was expected to run. The `scheduled_time` argument is optional.
127
147
 
128
148
  ```ruby
129
149
  class ExampleJob < ActiveJob::Base
130
- # @param task_name [String] This is the key used in the YAML file to define the task
131
- # @param time [Integer] The epoch time for when the job was scheduled to be run
132
- def perform(task_name, time)
133
- puts task_name
134
- puts Time.at(time)
150
+ # @param scheduled_time [Integer] The epoch time for when the job was scheduled to be run
151
+ def perform(scheduled_time)
152
+ puts Time.at(scheduled_time)
135
153
  end
136
154
  end
137
155
  ```
138
156
 
139
- When writing your jobs, you need to account for any possible server downtime.
140
- The most common downtime would be caused by Heroku's required daily restart.
157
+ ## Handling Expired Jobs
141
158
 
142
- To ensure that your tasks always run, the jobs are queued in advance and it's
143
- possible the jobs may not be executed at the exact time that you configured
144
- them to run. If there is extended downtime, your jobs may back up and there
145
- is no guarantee of the order they will be executed when your worker process
146
- comes back online.
159
+ If you assign the `expires_after` option to your task, you may want to know if
160
+ a job wasn't run because it expires. Add this block to an initializer file:
147
161
 
148
- Because there is no guarantee that the job is run at the exact time given in
149
- the configuration, the time the job was expected to run will be passed to
150
- the job so you can handle situations where the time it was run doesn't match
151
- the time it was expected to run.
162
+ ```ruby
163
+ # config/initializers/simple_scheduler.rb
164
+
165
+ # @param exception [SimpleScheduler::FutureJob::Expired]
166
+ SimpleScheduler.expired_task do |exception|
167
+ ExceptionNotifier.notify_exception(
168
+ exception,
169
+ data: {
170
+ task: exception.task.name,
171
+ scheduled: exception.scheduled_time,
172
+ actual: exception.run_time
173
+ }
174
+ )
175
+ end
176
+ ```
152
177
 
153
- ### How It Works
178
+ ## How It Works
154
179
 
155
180
  Once the rake task is added to Heroku Scheduler, the Simple Scheduler library
156
181
  will load the configuration file every 10 minutes, and ensure that each task
@@ -163,10 +188,10 @@ even if one of the two was executed during the 10 minute scheduler wait time.
163
188
 
164
189
  ### Server Downtime Example
165
190
 
166
- If you're using a gem like [clockwork](https://github.com/Rykian/clockwork), there is no way for the clock process to
167
- know that the task was never run. If your task is scheduled for `12:00:00`, your
168
- clock process could possibly be restarted at `11:59:59` and your dyno might not
169
- be available until `12:00:20`.
191
+ If you're using a gem like [clockwork](https://github.com/Rykian/clockwork),
192
+ there is no way for the clock process to know that the task was never run.
193
+ If your task is scheduled for `12:00:00`, your clock process could possibly
194
+ be restarted at `11:59:59` and your dyno might not be available until `12:00:20`.
170
195
 
171
196
  Simple Scheduler would have already enqueued the task hours before the task should actually
172
197
  run, so you still have to worry about the worker dyno restarting, but when the worker
@@ -186,6 +211,7 @@ daily_digest_task:
186
211
  class: "DailyDigestEmailJob"
187
212
  every: "15.minutes"
188
213
  at: "*:00"
214
+ expires_after: "23.hours"
189
215
  ```
190
216
 
191
217
  app/jobs/daily_digest_email_job.rb:
@@ -196,12 +222,11 @@ class DailyDigestEmailJob < ApplicationJob
196
222
 
197
223
  # Called by Simple Scheduler and is given the scheduled time so decisions can be made
198
224
  # based on when the job was scheduled to be run rather than when it was actually run.
199
- # @param task_name [String] This is the key used in the YAML file to define the task
200
- # @param time [Integer] The epoch time for when the job was scheduled to be run
201
- def perform(task_name, time)
225
+ # @param scheduled_time [Integer] The epoch time for when the job was scheduled to be run
226
+ def perform(scheduled_time)
202
227
  # Don't do this! This will be way too slow!
203
228
  User.find_each do |user|
204
- if user.digest_time == Time.at(time)
229
+ if user.digest_time == Time.at(scheduled_time)
205
230
  DigestMailer.daily(user).deliver_later
206
231
  end
207
232
  end
@@ -1,5 +1,6 @@
1
1
  require "active_job"
2
2
  require "sidekiq/api"
3
+ require_relative "./simple_scheduler/future_job"
3
4
  require_relative "./simple_scheduler/railtie"
4
5
  require_relative "./simple_scheduler/scheduler_job"
5
6
  require_relative "./simple_scheduler/task"
@@ -7,4 +8,24 @@ require_relative "./simple_scheduler/version"
7
8
 
8
9
  # Module for scheduling jobs at specific times using Sidekiq.
9
10
  module SimpleScheduler
11
+ # Used by a Rails initializer to handle expired tasks.
12
+ # SimpleScheduler.expired_task do |exception|
13
+ # ExceptionNotifier.notify_exception(
14
+ # exception,
15
+ # data: {
16
+ # task: exception.task.name,
17
+ # scheduled: exception.scheduled_time,
18
+ # actual: exception.run_time
19
+ # }
20
+ # )
21
+ # end
22
+ def self.expired_task(&block)
23
+ expired_task_blocks << block
24
+ end
25
+
26
+ # Blocks that should be called when a task doesn't run because it has expired.
27
+ # @return [Array]
28
+ def self.expired_task_blocks
29
+ @expired_task_blocks ||= []
30
+ end
10
31
  end
@@ -0,0 +1,83 @@
1
+ module SimpleScheduler
2
+ # Active Job class that wraps the scheduled job and determines if the job
3
+ # should still be run based on the scheduled time and when the job expires.
4
+ class FutureJob < ActiveJob::Base
5
+ # An error class that is raised if a job does not run because the run time is
6
+ # too late when compared to the scheduled run time.
7
+ # @!attribute run_time
8
+ # @return [Time] The actual run time
9
+ # @!attribute scheduled_time
10
+ # @return [Time] The scheduled run time
11
+ # @!attribute task
12
+ # @return [SimpleScheduler::Task] The expired task
13
+ class Expired < StandardError
14
+ attr_accessor :run_time, :scheduled_time, :task
15
+ end
16
+
17
+ rescue_from Expired, with: :handle_expired_task
18
+
19
+ # Perform the future job as defined by the task.
20
+ # @param task_params [Hash] The params from the scheduled task
21
+ # @param scheduled_time [Integer] The epoch time for when the job was scheduled to be run
22
+ def perform(task_params, scheduled_time)
23
+ @task = Task.new(task_params)
24
+ @scheduled_time = Time.at(scheduled_time).in_time_zone(@task.time_zone)
25
+ raise Expired if expired?
26
+
27
+ if @task.job_class.included_modules.include?(Sidekiq::Worker)
28
+ queue_sidekiq_worker
29
+ else
30
+ queue_active_job
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ # The duration between the scheduled run time and actual run time that
37
+ # will cause the job to expire. Expired jobs will not be executed.
38
+ def expire_duration
39
+ split_duration = @task.expires_after.split(".")
40
+ duration = split_duration[0].to_i
41
+ duration_units = split_duration[1]
42
+ duration.send(duration_units)
43
+ end
44
+
45
+ # Returns whether or not the job has expired based on the time
46
+ # between the scheduled run time and the current time.
47
+ # @return [Boolean]
48
+ def expired?
49
+ return false if @task.expires_after.blank?
50
+ expire_duration.from_now(@scheduled_time) < Time.now.in_time_zone(@task.time_zone)
51
+ end
52
+
53
+ # Handle the expired task by passing the task and run time information
54
+ # to a block that can be creating in a Rails initializer file.
55
+ def handle_expired_task(exception)
56
+ exception.run_time = Time.now.in_time_zone(@task.time_zone)
57
+ exception.scheduled_time = @scheduled_time
58
+ exception.task = @task
59
+
60
+ SimpleScheduler.expired_task_blocks.each do |block|
61
+ block.call(exception)
62
+ end
63
+ end
64
+
65
+ # Queue the job for immediate execution using Active Job.
66
+ def queue_active_job
67
+ if @task.job_class.instance_method(:perform).arity > 0
68
+ @task.job_class.perform_later(@scheduled_time.to_i)
69
+ else
70
+ @task.job_class.perform_later
71
+ end
72
+ end
73
+
74
+ # Queue the job for immediate execution using Sidekiq.
75
+ def queue_sidekiq_worker
76
+ if @task.job_class.instance_method(:perform).arity > 0
77
+ @task.job_class.perform_async(@scheduled_time.to_i)
78
+ else
79
+ @task.job_class.perform_async
80
+ end
81
+ end
82
+ end
83
+ end
@@ -1,34 +1,35 @@
1
1
  module SimpleScheduler
2
2
  # Active Job class that queues jobs defined in the config file.
3
3
  class SchedulerJob < ActiveJob::Base
4
+ # Accepts a file path to read the scheduler configuration.
5
+ # @param config_path [String]
6
+ def perform(config_path = nil)
7
+ config_path ||= "config/simple_scheduler.yml"
8
+ load_config(config_path)
9
+ queue_future_jobs
10
+ end
11
+
12
+ private
13
+
4
14
  # Load the global scheduler config from the YAML file.
5
15
  # @param config_path [String]
6
16
  def load_config(config_path)
7
17
  @config = YAML.load_file(config_path)
8
18
  @queue_ahead = @config["queue_ahead"] || Task::DEFAULT_QUEUE_AHEAD_MINUTES
9
- @time_zone = @config["tz"] ? ActiveSupport::TimeZone.new(@config["tz"]) : Time.zone
19
+ @time_zone = @config["tz"] || Time.zone.tzinfo.name
10
20
  @config.delete("queue_ahead")
11
21
  @config.delete("tz")
12
22
  end
13
23
 
14
- # Accepts a file path to read the scheduler configuration.
15
- # @param config_path [String]
16
- def perform(config_path = nil)
17
- config_path ||= "config/simple_scheduler.yml"
18
- load_config(config_path)
19
- queue_future_jobs
20
- end
21
-
22
24
  # Queue each of the future jobs into Sidekiq from the defined tasks.
23
25
  def queue_future_jobs
24
26
  tasks.each do |task|
25
27
  new_run_times = task.future_run_times - task.existing_run_times
26
28
  next if new_run_times.empty?
27
29
 
28
- if task.job_class.included_modules.include?(Sidekiq::Worker)
29
- queue_future_sidekiq_workers(task, new_run_times)
30
- else
31
- queue_future_active_jobs(task, new_run_times)
30
+ # Schedule the new run times using the future job wrapper.
31
+ new_run_times.each do |time|
32
+ SimpleScheduler::FutureJob.set(wait_until: time).perform_later(task.params, time.to_i)
32
33
  end
33
34
  end
34
35
  end
@@ -44,25 +45,5 @@ module SimpleScheduler
44
45
  Task.new(task_params)
45
46
  end
46
47
  end
47
-
48
- private
49
-
50
- # Queues jobs in the future using Active Job based on the task options.
51
- # @param task [SimpleScheduler::Task]
52
- # @param run_times [Array<Time>]
53
- def queue_future_active_jobs(task, run_times)
54
- run_times.each do |time|
55
- task.job_class.set(wait_until: time).perform_later(task.name, time.to_i)
56
- end
57
- end
58
-
59
- # Queues jobs in the future using Sidekiq based on the task options.
60
- # @param task [SimpleScheduler::Task]
61
- # @param run_times [Array<Time>]
62
- def queue_future_sidekiq_workers(task, run_times)
63
- run_times.each do |time|
64
- task.job_class.perform_at(time, task.name, time.to_i)
65
- end
66
- end
67
48
  end
68
49
  end
@@ -1,8 +1,28 @@
1
1
  module SimpleScheduler
2
2
  # Class for parsing each task in the scheduler config YAML file and returning
3
3
  # the values needed to schedule the task in the future.
4
+ #
5
+ # @!attribute at
6
+ # @return [String] The starting time for the interval
7
+ # @!attribute expires_after
8
+ # @return [String] The time between the scheduled and actual run time that should cause the job not to run
9
+ # @!attribute frequency
10
+ # @return [ActiveSupport::Duration] How often the job will be run
11
+ # @!attribute [r] job_class
12
+ # @return [Class] The class of the job or worker
13
+ # @!attribute [r] job_class_name
14
+ # @return [String] The class name of the job or worker
15
+ # @!attribute name
16
+ # @return [String] The name of the task as defined in the YAML config
17
+ # @!attribute [r] params
18
+ # @return [Hash] The params used to create the task
19
+ # @!attribute queue_ahead
20
+ # @return [String] The name of the task as defined in the YAML config
21
+ # @!attribute time_zone
22
+ # @return [ActiveSupport::TimeZone] The time zone to use when parsing the `at` option
4
23
  class Task
5
- attr_accessor :at, :frequency, :job_class, :job_class_name, :name, :queue_ahead, :time_zone
24
+ attr_reader :at, :expires_after, :frequency, :job_class, :job_class_name
25
+ attr_reader :name, :params, :queue_ahead, :time_zone
6
26
 
7
27
  AT_PATTERN = /(Sun|Mon|Tue|Wed|Thu|Fri|Sat)?\s?(?:\*{1,2}|(\d{1,2})):(\d{1,2})/
8
28
  DAYS = %w(Sun Mon Tue Wed Thu Fri Sat).freeze
@@ -13,25 +33,30 @@ module SimpleScheduler
13
33
  # @option params [String] :class The class of the Active Job or Sidekiq Worker
14
34
  # @option params [String] :every How frequently the job will be performed
15
35
  # @option params [String] :at The starting time for the interval
36
+ # @option params [String] :expires_after The time between the scheduled and actual run time that should cause the job not to run
16
37
  # @option params [Integer] :queue_ahead The number of minutes that jobs should be queued in the future
17
38
  # @option params [String] :task_name The name of the task as defined in the YAML config
18
- # @option params [ActiveSupport::TimeZone] :tz The time zone to use when parsing the `at` option
39
+ # @option params [String] :tz The time zone to use when parsing the `at` option
19
40
  def initialize(params)
20
41
  validate_params!(params)
21
- @at = params[:at]
22
- @frequency = parse_frequency(params[:every])
42
+ @at = params[:at]
43
+ @expires_after = params[:expires_after]
44
+ @frequency = parse_frequency(params[:every])
23
45
  @job_class_name = params[:class]
24
- @job_class = @job_class_name.constantize
25
- @queue_ahead = params[:queue_ahead] || DEFAULT_QUEUE_AHEAD_MINUTES
26
- @name = params[:name] || @job_class_name
27
- @time_zone = params[:tz] || Time.zone
46
+ @job_class = @job_class_name.constantize
47
+ @queue_ahead = params[:queue_ahead] || DEFAULT_QUEUE_AHEAD_MINUTES
48
+ @name = params[:name]
49
+ @params = params
50
+ @time_zone = params[:tz] ? ActiveSupport::TimeZone.new(params[:tz]) : Time.zone
28
51
  end
29
52
 
30
53
  # Returns an array of existing jobs matching the job class of the task.
31
54
  # @return [Array<Sidekiq::SortedEntry>]
32
55
  def existing_jobs
33
56
  @existing_jobs ||= SimpleScheduler::Task.scheduled_set.select do |job|
34
- job.display_class == @job_class_name && job.display_args[0] == @name
57
+ next unless job.display_class == "SimpleScheduler::FutureJob"
58
+ task_params = job.display_args[0]
59
+ task_params[:class] == @job_class_name && task_params[:name] == @name
35
60
  end.to_a
36
61
  end
37
62
 
@@ -120,6 +145,7 @@ module SimpleScheduler
120
145
  end
121
146
 
122
147
  def validate_params!(params)
148
+ params[:name] ||= params[:class]
123
149
  raise ArgumentError, "Missing param `class` specifying the class of the job to run." unless params.key?(:class)
124
150
  raise ArgumentError, "Missing param `every` specifying how often the job should run." unless params.key?(:every)
125
151
  end
@@ -1,3 +1,3 @@
1
1
  module SimpleScheduler
2
- VERSION = "0.1.0".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
metadata CHANGED
@@ -1,111 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_scheduler
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
  - Brian Pattison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-07 00:00:00.000000000 Z
11
+ date: 2016-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '4.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: sidekiq
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '4.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '4.2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec-rails
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rubocop
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: simplecov
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: simplecov-rcov
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: timecop
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - '>='
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - '>='
94
+ - - ">="
109
95
  - !ruby/object:Gem::Version
110
96
  version: '0'
111
97
  description: |2
@@ -118,15 +104,16 @@ executables: []
118
104
  extensions: []
119
105
  extra_rdoc_files: []
120
106
  files:
107
+ - MIT-LICENSE
108
+ - README.md
109
+ - Rakefile
110
+ - lib/simple_scheduler.rb
111
+ - lib/simple_scheduler/future_job.rb
121
112
  - lib/simple_scheduler/railtie.rb
122
113
  - lib/simple_scheduler/scheduler_job.rb
123
114
  - lib/simple_scheduler/task.rb
124
115
  - lib/simple_scheduler/version.rb
125
- - lib/simple_scheduler.rb
126
116
  - lib/tasks/simple_scheduler_tasks.rake
127
- - MIT-LICENSE
128
- - Rakefile
129
- - README.md
130
117
  homepage: https://github.com/simplymadeapps/simple_scheduler
131
118
  licenses:
132
119
  - MIT
@@ -137,17 +124,17 @@ require_paths:
137
124
  - lib
138
125
  required_ruby_version: !ruby/object:Gem::Requirement
139
126
  requirements:
140
- - - '>='
127
+ - - ">="
141
128
  - !ruby/object:Gem::Version
142
129
  version: '0'
143
130
  required_rubygems_version: !ruby/object:Gem::Requirement
144
131
  requirements:
145
- - - '>='
132
+ - - ">="
146
133
  - !ruby/object:Gem::Version
147
134
  version: '0'
148
135
  requirements: []
149
136
  rubyforge_project:
150
- rubygems_version: 2.0.14.1
137
+ rubygems_version: 2.5.1
151
138
  signing_key:
152
139
  specification_version: 4
153
140
  summary: An enhancement for Heroku Scheduler + Sidekiq for scheduling jobs at specific