skyrunner 0.0.1
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 +7 -0
- data/.gitignore +18 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +4 -0
- data/Rakefile +1 -0
- data/bin/skyrunner +60 -0
- data/jobs/example_job.rb +28 -0
- data/lib/skyrunner/job.rb +145 -0
- data/lib/skyrunner/version.rb +3 -0
- data/lib/skyrunner.rb +187 -0
- data/skyrunner.gemspec +28 -0
- metadata +143 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8928e9988b2964b41819825a1b47adf1a458338d
|
4
|
+
data.tar.gz: cfbd389efd794094ce4be1f465dfff0252b976d4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: befca88f0e29654d83dafb5539a973c5b9f39fd52db3e72edf34e2ce55e529e738691835701c308dc62ebb9057133998c41ffd710c806e72e238df53bf8e3400
|
7
|
+
data.tar.gz: e180a3849b4f5b1891eb681e1786826464612be54dbc523328b2c442c9390e23b9bacc869ba9049ac4bf9fbbf2ca7ab54353fc35fb7cdbd01b245fe304bfca8f
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Greg Fodor
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/skyrunner
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.dirname(__FILE__) + "/../lib"
|
4
|
+
|
5
|
+
require "skyrunner"
|
6
|
+
require "trollop"
|
7
|
+
|
8
|
+
logger = Log4r::Logger.new("sky")
|
9
|
+
logger.outputters << Log4r::StdoutOutputter.new("out")
|
10
|
+
logger.level = Log4r::DEBUG
|
11
|
+
|
12
|
+
SkyRunner.logger = logger
|
13
|
+
|
14
|
+
trap("INT") do
|
15
|
+
SkyRunner.stop_consuming!
|
16
|
+
end
|
17
|
+
|
18
|
+
trap("TERM") do
|
19
|
+
SkyRunner.stop_consuming!
|
20
|
+
end
|
21
|
+
|
22
|
+
opts = Trollop::options do
|
23
|
+
banner <<-END
|
24
|
+
Runs logical jobs (made up of tasks) coordinated via AWS SQS & DynamoDB.
|
25
|
+
|
26
|
+
Usage:
|
27
|
+
skyrunner [options] <command>
|
28
|
+
|
29
|
+
Valid commands:
|
30
|
+
|
31
|
+
consume - Starts consuming tasks.
|
32
|
+
init - Creates DynamoDB table and SQS queue for SkyRunner.
|
33
|
+
purge - Purges and re-creates DynamoDB table and SQS queue for SkyRunner. (Destructive!)
|
34
|
+
END
|
35
|
+
|
36
|
+
opt :dynamo_db_table_name, "DynamoDB table to use for job state.", default: "skyrunner_jobs", type: :string
|
37
|
+
opt :sqs_queue_name, "SQS queue use for tasks.", default: "skyrunner_tasks", type: :string
|
38
|
+
opt :namespace, "Namespace of jobs to consume.", default: "default", type: :string
|
39
|
+
opt :batch_size, "Number of tasks to consume per batch.", default: 10
|
40
|
+
end
|
41
|
+
|
42
|
+
SkyRunner.dynamo_db_table_name = opts[:dynamo_db_table_name]
|
43
|
+
SkyRunner.sqs_queue_name = opts[:sqs_queue_name]
|
44
|
+
SkyRunner.job_namespace = opts[:namespace]
|
45
|
+
SkyRunner.consumer_batch_size = opts[:batch_size].to_i
|
46
|
+
|
47
|
+
COMMANDS = ["init", "purge", "consume"]
|
48
|
+
|
49
|
+
Trollop::die "Must specify command" unless COMMANDS.include?(ARGV[0])
|
50
|
+
|
51
|
+
command = ARGV[0]
|
52
|
+
|
53
|
+
case command
|
54
|
+
when "init"
|
55
|
+
SkyRunner.init!
|
56
|
+
when "purge"
|
57
|
+
SkyRunner.init!(purge: true)
|
58
|
+
when "consume"
|
59
|
+
SkyRunner.consume!
|
60
|
+
end
|
data/jobs/example_job.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "skyrunner"
|
2
|
+
|
3
|
+
module ExampleJobModule
|
4
|
+
class ExampleJob
|
5
|
+
include SkyRunner::Job
|
6
|
+
|
7
|
+
on_completed :print_completed
|
8
|
+
on_failed :print_failed
|
9
|
+
|
10
|
+
def run(number_of_tasks: nil)
|
11
|
+
1.upto(number_of_tasks).each do |n|
|
12
|
+
yield :print_number, task_number: n
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def print_number(task_number: nil)
|
17
|
+
puts "Ran rask #{task_number}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def print_completed(number_of_tasks: nil)
|
21
|
+
puts "Completed with #{number_of_tasks}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def print_failed(number_of_tasks: nil)
|
25
|
+
puts "Failed with #{number_of_tasks}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module SkyRunner::Job
|
2
|
+
attr_accessor :skyrunner_job_id
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def on_completed(methods)
|
10
|
+
add_job_event_methods(methods, :completed)
|
11
|
+
end
|
12
|
+
|
13
|
+
def on_failed(methods)
|
14
|
+
add_job_event_methods(methods, :failed)
|
15
|
+
end
|
16
|
+
|
17
|
+
def job_event_methods
|
18
|
+
@_job_event_methods ||= {}
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def add_job_event_methods(methods, type)
|
24
|
+
methods = Array(methods)
|
25
|
+
job_event_methods[type] ||= []
|
26
|
+
job_event_methods[type].concat(methods.map(&:to_sym))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def execute!(args = {})
|
31
|
+
job_id = SecureRandom.hex
|
32
|
+
self.skyrunner_job_id = job_id
|
33
|
+
|
34
|
+
table = SkyRunner.dynamo_db_table
|
35
|
+
queue = SkyRunner.sqs_queue
|
36
|
+
|
37
|
+
record = table.items.put(job_id: job_id, namespace: SkyRunner.job_namespace, class: self.class.name, args: args.to_json, total_tasks: 1, completed_tasks: 0, done: 0, failed: 0)
|
38
|
+
|
39
|
+
pending_args = []
|
40
|
+
|
41
|
+
flush = lambda do
|
42
|
+
messages = pending_args.map do |task_args|
|
43
|
+
{ job_id: job_id, task_id: SecureRandom.hex, task_args: task_args }.to_json
|
44
|
+
end
|
45
|
+
|
46
|
+
dropped_message_count = 0
|
47
|
+
pending_args.clear
|
48
|
+
|
49
|
+
begin
|
50
|
+
queue.batch_send(messages)
|
51
|
+
rescue AWS::SQS::Errors::BatchSendError => e
|
52
|
+
dropped_message_count = e.errors.size
|
53
|
+
|
54
|
+
# Re-add dropped args
|
55
|
+
e.errors.each do |error|
|
56
|
+
pending_args << JSON.parse(error[:message_body])["task_args"]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
record.attributes.add({ total_tasks: messages.size - dropped_message_count })
|
61
|
+
end
|
62
|
+
|
63
|
+
self.run(args) do |*task_args|
|
64
|
+
pending_args << task_args
|
65
|
+
|
66
|
+
if pending_args.size >= SkyRunner::SQS_MAX_BATCH_SIZE
|
67
|
+
1.upto(5) do
|
68
|
+
flush.()
|
69
|
+
sleep 5 if pending_args.size > 0
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
1.upto(5) do
|
75
|
+
flush.() if pending_args.size > 0
|
76
|
+
sleep 5 if pending_args.size > 0
|
77
|
+
end
|
78
|
+
|
79
|
+
handle_task_completed!
|
80
|
+
end
|
81
|
+
|
82
|
+
def consume!(task_args)
|
83
|
+
begin
|
84
|
+
self.send(task_args[0].to_sym, task_args[1].symbolize_keys)
|
85
|
+
handle_task_completed!
|
86
|
+
rescue Exception => e
|
87
|
+
handle_task_failed! rescue nil
|
88
|
+
raise
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def dynamo_db_record
|
95
|
+
SkyRunner.dynamo_db_table.items[self.skyrunner_job_id]
|
96
|
+
end
|
97
|
+
|
98
|
+
def handle_task_failed!
|
99
|
+
return false unless self.skyrunner_job_id
|
100
|
+
|
101
|
+
begin
|
102
|
+
record = dynamo_db_record
|
103
|
+
record.attributes.add({ failed: 1 })
|
104
|
+
|
105
|
+
(self.class.job_event_methods[:failed] || []).each do |method|
|
106
|
+
if self.method(method).arity == 0 && self.method(method).parameters.size == 0
|
107
|
+
self.send(method)
|
108
|
+
else
|
109
|
+
self.send(method, JSON.parse(record.attributes["args"]).symbolize_keys)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
rescue Exception => e
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def handle_task_completed!
|
117
|
+
return false unless self.skyrunner_job_id
|
118
|
+
|
119
|
+
record = dynamo_db_record
|
120
|
+
|
121
|
+
new_attributes = record.attributes.add({ completed_tasks: 1 }, return: :all_new)
|
122
|
+
|
123
|
+
if new_attributes["total_tasks"] == new_attributes["completed_tasks"]
|
124
|
+
begin
|
125
|
+
if_condition = { completed_tasks: new_attributes["total_tasks"], done: 0 }
|
126
|
+
|
127
|
+
record.attributes.update(if: if_condition) do |u|
|
128
|
+
u.add(done: 1)
|
129
|
+
end
|
130
|
+
|
131
|
+
(self.class.job_event_methods[:completed] || []).each do |method|
|
132
|
+
if self.method(method).arity == 0 && self.method(method).parameters.size == 0
|
133
|
+
self.send(method)
|
134
|
+
else
|
135
|
+
self.send(method, JSON.parse(record.attributes["args"]).symbolize_keys)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
rescue AWS::DynamoDB::Errors::ConditionalCheckFailedException => e
|
139
|
+
# This is OK, we had a double finisher.
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
true
|
144
|
+
end
|
145
|
+
end
|
data/lib/skyrunner.rb
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
require "skyrunner/version"
|
2
|
+
require "aws-sdk"
|
3
|
+
require "active_support"
|
4
|
+
require "active_support/core_ext"
|
5
|
+
require "log4r"
|
6
|
+
require "json"
|
7
|
+
require "set"
|
8
|
+
|
9
|
+
module SkyRunner
|
10
|
+
SQS_MAX_BATCH_SIZE = 10 # Constant defined by AWS
|
11
|
+
|
12
|
+
def self.setup
|
13
|
+
yield self
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.init!(params = {})
|
17
|
+
table = self.dynamo_db_table
|
18
|
+
|
19
|
+
if !table.exists? || params[:purge]
|
20
|
+
table_name = SkyRunner.dynamo_db_table_name
|
21
|
+
|
22
|
+
if table.exists? && params[:purge]
|
23
|
+
SkyRunner.log :warn, "Purging DynamoDB table #{table_name}."
|
24
|
+
table.delete
|
25
|
+
|
26
|
+
sleep 1 while table.exists?
|
27
|
+
end
|
28
|
+
|
29
|
+
SkyRunner.log :info, "Creating DynamoDB table #{table_name}."
|
30
|
+
|
31
|
+
table = dynamo_db.tables.create(table_name,
|
32
|
+
SkyRunner.dynamo_db_read_capacity,
|
33
|
+
SkyRunner.dynamo_db_write_capacity,
|
34
|
+
hash_key: { job_id: :string })
|
35
|
+
|
36
|
+
sleep 1 while table.status == :creating
|
37
|
+
end
|
38
|
+
|
39
|
+
queue = self.sqs_queue
|
40
|
+
|
41
|
+
if !queue || params[:purge]
|
42
|
+
queue_name = SkyRunner.sqs_queue_name
|
43
|
+
|
44
|
+
if queue && params[:purge]
|
45
|
+
SkyRunner.log :warn, "Purging SQS queue #{queue_name}. Waiting 65 seconds to re-create."
|
46
|
+
queue.delete
|
47
|
+
|
48
|
+
sleep 65
|
49
|
+
end
|
50
|
+
|
51
|
+
SkyRunner.log :info, "Creating SQS queue #{queue_name}."
|
52
|
+
|
53
|
+
queue = sqs.queues.create(queue_name,
|
54
|
+
visibility_timeout: SkyRunner.sqs_visibility_timeout,
|
55
|
+
message_retention_period: SkyRunner.sqs_message_retention_period)
|
56
|
+
end
|
57
|
+
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.consume!(&block)
|
62
|
+
queue = sqs_queue
|
63
|
+
table = dynamo_db_table
|
64
|
+
|
65
|
+
raise "Queue #{SkyRunner::sqs_queue_name} not found. Try running 'skyrunner init'" unless queue
|
66
|
+
raise "DynamoDB table #{SkyRunner::dynamo_db_table_name} not found. Try running 'skyrunner init'" unless table && table.exists?
|
67
|
+
|
68
|
+
log :info, "Consumer started."
|
69
|
+
|
70
|
+
loop do
|
71
|
+
return true if stop_consuming
|
72
|
+
|
73
|
+
received_messages = []
|
74
|
+
|
75
|
+
queue.receive_messages(limit: [1, [SkyRunner.consumer_batch_size, SQS_MAX_BATCH_SIZE].min].max, wait_time_seconds: 15) do |message|
|
76
|
+
received_messages << [message, JSON.parse(message.body)]
|
77
|
+
end
|
78
|
+
|
79
|
+
next unless received_messages.size > 0
|
80
|
+
|
81
|
+
failed = false
|
82
|
+
|
83
|
+
table.batch_get(:all, received_messages.map { |m| m[1]["job_id"] }.uniq, consistent_read: true) do |record|
|
84
|
+
break if stop_consuming
|
85
|
+
|
86
|
+
received_messages.select { |m| m[1]["job_id"] == record["job_id"] }.each_with_index do |received_message|
|
87
|
+
break if stop_consuming
|
88
|
+
|
89
|
+
message = received_message[1]
|
90
|
+
job_id = message["job_id"]
|
91
|
+
|
92
|
+
if record["namespace"] == SkyRunner.job_namespace && record["failed"] == 0 && !failed
|
93
|
+
start_time = Time.now
|
94
|
+
|
95
|
+
begin
|
96
|
+
klass = Kernel.const_get(record["class"])
|
97
|
+
|
98
|
+
task_args = message["task_args"]
|
99
|
+
log :info, "Run Task: #{task_args} Job: #{job_id}"
|
100
|
+
|
101
|
+
job = klass.new
|
102
|
+
job.skyrunner_job_id = job_id
|
103
|
+
|
104
|
+
begin
|
105
|
+
job.consume!(task_args)
|
106
|
+
received_message[0].delete
|
107
|
+
|
108
|
+
yield false if block_given?
|
109
|
+
rescue Exception => e
|
110
|
+
failed = true
|
111
|
+
log :error, "Task Failed: #{task_args} Job: #{job_id} #{e.message} #{e.backtrace.join("\n")}"
|
112
|
+
yield e if block_given?
|
113
|
+
end
|
114
|
+
rescue NameError => e
|
115
|
+
failed = true
|
116
|
+
log :error, "Task Failed: No such class #{record["class"]} #{e.message}"
|
117
|
+
yield e if block_given?
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.dynamo_db_table
|
126
|
+
dynamo_db.tables[SkyRunner.dynamo_db_table_name].tap do |table|
|
127
|
+
table.load_schema if table && table.exists?
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.sqs_queue
|
132
|
+
begin
|
133
|
+
sqs.queues.named(SkyRunner.sqs_queue_name)
|
134
|
+
rescue AWS::SQS::Errors::NonExistentQueue => e
|
135
|
+
return nil
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.log(type, message)
|
140
|
+
SkyRunner.logger.send(type, "[SkyRunner] #{message}")
|
141
|
+
end
|
142
|
+
|
143
|
+
mattr_accessor :dynamo_db_table_name
|
144
|
+
@@dynamo_db_table_name = "skyrunner_jobs"
|
145
|
+
|
146
|
+
mattr_accessor :dynamo_db_read_capacity
|
147
|
+
@@dynamo_db_read_capacity = 10
|
148
|
+
|
149
|
+
mattr_accessor :dynamo_db_write_capacity
|
150
|
+
@@dynamo_db_write_capacity = 10
|
151
|
+
|
152
|
+
mattr_accessor :sqs_queue_name
|
153
|
+
@@sqs_queue_name = "skyrunner_tasks"
|
154
|
+
|
155
|
+
mattr_accessor :sqs_visibility_timeout
|
156
|
+
@@sqs_visibility_timeout = 90
|
157
|
+
|
158
|
+
mattr_accessor :sqs_message_retention_period
|
159
|
+
@@sqs_message_retention_period = 345600
|
160
|
+
|
161
|
+
mattr_accessor :job_namespace
|
162
|
+
@@job_namespace = "default"
|
163
|
+
|
164
|
+
mattr_accessor :consumer_batch_size
|
165
|
+
@@consumer_batch_size = 10
|
166
|
+
|
167
|
+
mattr_accessor :logger
|
168
|
+
@@logger = Log4r::Logger.new("skyrunner")
|
169
|
+
|
170
|
+
mattr_accessor :stop_consuming
|
171
|
+
|
172
|
+
def self.stop_consuming!
|
173
|
+
SkyRunner::stop_consuming = true
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
|
178
|
+
def self.dynamo_db
|
179
|
+
@dynamo_db ||= AWS::DynamoDB.new
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.sqs
|
183
|
+
@sqs ||= AWS::SQS.new
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
require "skyrunner/job"
|
data/skyrunner.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'skyrunner/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "skyrunner"
|
8
|
+
spec.version = Skyrunner::VERSION
|
9
|
+
spec.authors = ["Greg Fodor"]
|
10
|
+
spec.email = ["gfodor@gmail.com"]
|
11
|
+
spec.description = %q{SkyRunner runs logical jobs that are broken up into tasks via Amazon SQS and DynamoDB.}
|
12
|
+
spec.summary = %q{SkyRunner runs logical jobs that are broken up into tasks via Amazon SQS and DynamoDB.}
|
13
|
+
spec.homepage = "http://github.com/gfodor/skyrunner"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
|
24
|
+
spec.add_runtime_dependency "aws-sdk"
|
25
|
+
spec.add_runtime_dependency "activesupport", "~> 4.0"
|
26
|
+
spec.add_runtime_dependency "log4r"
|
27
|
+
spec.add_runtime_dependency "trollop"
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: skyrunner
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Greg Fodor
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: aws-sdk
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: log4r
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: trollop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: SkyRunner runs logical jobs that are broken up into tasks via Amazon
|
98
|
+
SQS and DynamoDB.
|
99
|
+
email:
|
100
|
+
- gfodor@gmail.com
|
101
|
+
executables:
|
102
|
+
- skyrunner
|
103
|
+
extensions: []
|
104
|
+
extra_rdoc_files: []
|
105
|
+
files:
|
106
|
+
- .gitignore
|
107
|
+
- Gemfile
|
108
|
+
- LICENSE.txt
|
109
|
+
- README.md
|
110
|
+
- Rakefile
|
111
|
+
- bin/skyrunner
|
112
|
+
- jobs/example_job.rb
|
113
|
+
- lib/skyrunner.rb
|
114
|
+
- lib/skyrunner/job.rb
|
115
|
+
- lib/skyrunner/version.rb
|
116
|
+
- skyrunner.gemspec
|
117
|
+
homepage: http://github.com/gfodor/skyrunner
|
118
|
+
licenses:
|
119
|
+
- MIT
|
120
|
+
metadata: {}
|
121
|
+
post_install_message:
|
122
|
+
rdoc_options: []
|
123
|
+
require_paths:
|
124
|
+
- lib
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - '>='
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
requirements: []
|
136
|
+
rubyforge_project:
|
137
|
+
rubygems_version: 2.0.6
|
138
|
+
signing_key:
|
139
|
+
specification_version: 4
|
140
|
+
summary: SkyRunner runs logical jobs that are broken up into tasks via Amazon SQS
|
141
|
+
and DynamoDB.
|
142
|
+
test_files: []
|
143
|
+
has_rdoc:
|