simple_scheduler 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|