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 +4 -4
- data/README.md +77 -52
- data/lib/simple_scheduler.rb +21 -0
- data/lib/simple_scheduler/future_job.rb +83 -0
- data/lib/simple_scheduler/scheduler_job.rb +14 -33
- data/lib/simple_scheduler/task.rb +35 -9
- data/lib/simple_scheduler/version.rb +1 -1
- metadata +22 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f15bb865956e8b2d8b84e65ba2baf7386333a5f
|
4
|
+
data.tar.gz: bf3cd7c9bac2b2d9d2085b8d4b4c55000977c98f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
###
|
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
|
-
```
|
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
|
-
|
103
|
-
**:00
|
104
|
-
|
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
|
-
|
127
|
+
#### :expires_after (optional)
|
110
128
|
|
111
|
-
|
112
|
-
|
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
|
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
|
-
|
136
|
+
```yml
|
137
|
+
"59.minutes"
|
138
|
+
"23.hours"
|
120
139
|
```
|
121
140
|
|
122
141
|
## Writing Your Jobs
|
123
142
|
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|
131
|
-
|
132
|
-
|
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
|
-
|
140
|
-
The most common downtime would be caused by Heroku's required daily restart.
|
157
|
+
## Handling Expired Jobs
|
141
158
|
|
142
|
-
|
143
|
-
|
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
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
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
|
-
|
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),
|
167
|
-
know that the task was never run.
|
168
|
-
|
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
|
200
|
-
|
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(
|
229
|
+
if user.digest_time == Time.at(scheduled_time)
|
205
230
|
DigestMailer.daily(user).deliver_later
|
206
231
|
end
|
207
232
|
end
|
data/lib/simple_scheduler.rb
CHANGED
@@ -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"]
|
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
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
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 [
|
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
|
22
|
-
@
|
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
|
25
|
-
@queue_ahead
|
26
|
-
@name
|
27
|
-
@
|
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
|
-
|
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
|
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.
|
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-
|
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.
|
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
|