simple_job 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +5 -0
- data/LICENSE.txt +7 -0
- data/README.rdoc +101 -0
- data/lib/simple_job/job_definition.rb +180 -0
- data/lib/simple_job/job_queue.rb +111 -0
- data/lib/simple_job/sqs_job_queue.rb +97 -0
- data/lib/simple_job/version.rb +3 -0
- data/lib/simple_job.rb +7 -0
- metadata +93 -0
data/CHANGELOG.rdoc
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2012 RevPAR Collective, Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
= Simple Job
|
2
|
+
|
3
|
+
A gem containing libraries that support running background jobs or tasks. It's designed to make it easy to:
|
4
|
+
|
5
|
+
* Define a job
|
6
|
+
* Enqueue a job
|
7
|
+
* Poll for and execute jobs
|
8
|
+
|
9
|
+
It is architected to support multiple types of queue implementations, but currently, it only includes an implementation using AWS SQS (http://aws.amazon.com/sqs/). Alternate queue implementations could be plugged in by the client using lib/simple_job/sqs_job_queue.rb as an example.
|
10
|
+
|
11
|
+
The AWS SQS queue implementation requires the aws-sdk gem, which must be initialized (by calling AWS.config) for this API to be capable of enqueuing or polling for jobs.
|
12
|
+
|
13
|
+
|
14
|
+
== Queue Configuration
|
15
|
+
|
16
|
+
Queue configuration must be done by both the client and the server.
|
17
|
+
|
18
|
+
Only the queues that will be used by each must be defined (a client may configure a subset of the queues used by the server, so long as it configures all the queues that it uses).
|
19
|
+
|
20
|
+
SQSJobQueue is the queue implementation used by default. This may be overridden by calling SimpleJob::JobQueue.config :implementation => 'my_queue_type'
|
21
|
+
|
22
|
+
=== Minimal configuration - specify queue prefix and define one default queue
|
23
|
+
|
24
|
+
SimpleJob::SQSJobQueue.config :queue_prefix => 'my-job'
|
25
|
+
SimpleJob::SQSJobQueue.define_queue 'normal', :default => true
|
26
|
+
|
27
|
+
=== Complex configuration with explicit queue implementation, non-rails-defined environment, and multiple queues
|
28
|
+
|
29
|
+
SimpleJob::JobQueue.config :implementation => 'sqs'
|
30
|
+
SimpleJob::SQSJobQueue.config :queue_prefix => 'my-job', :environment => 'production'
|
31
|
+
SimpleJob::SQSJobQueue.define_queue 'normal', :visibility_timeout => 60, :default => true
|
32
|
+
SimpleJob::SQSJobQueue.define_queue 'high-priority', :visibility_timeout => 10
|
33
|
+
SimpleJob::SQSJobQueue.define_queue 'long-running', :visibility_timeout => 3600
|
34
|
+
|
35
|
+
|
36
|
+
== Job Definition
|
37
|
+
|
38
|
+
class FooSender
|
39
|
+
include SimpleJob::JobDefinition
|
40
|
+
|
41
|
+
simple_job_attribute :target, :foo_content # defines getters/setters for each, and
|
42
|
+
# adds them to serialized message
|
43
|
+
|
44
|
+
validates :target, :presence => true # standard ActiveModel validation
|
45
|
+
|
46
|
+
def execute
|
47
|
+
puts "#{foo_content} -> #{target}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
== Job Client Usage
|
53
|
+
|
54
|
+
=== Typical usage of default queue
|
55
|
+
|
56
|
+
You may call #enqueue with no arguments, in which case JobQueue.default will be used.
|
57
|
+
|
58
|
+
f = FooSender.new(:target => 'joe', :foo_content => 'foo!') # can also assign attributes with f.target=, f.foo_content=
|
59
|
+
if f.enqueue
|
60
|
+
puts 'i just sent some foo to joe!'
|
61
|
+
else
|
62
|
+
puts "the following errors occurred: #{f.errors.full_messages.join('; ')}"
|
63
|
+
end
|
64
|
+
|
65
|
+
json = f.to_json # { "type": "foo_sender", "version": "1", "data": { "target": "joe", "foo_content": "foo!" } }
|
66
|
+
f_copy = FooSender.new.from_json(json)
|
67
|
+
|
68
|
+
=== Simple usage with explicit queue
|
69
|
+
|
70
|
+
To explicitly specify the queue to use, simply specify its type identifier (defined in SQSJobQueue.define_queue declaration) when calling enqueue.
|
71
|
+
|
72
|
+
f = FooSender.new
|
73
|
+
f.target = 'bob'
|
74
|
+
f.foo_content = 'foo!'
|
75
|
+
f.enqueue!('normal') # raises exception if operation fails
|
76
|
+
|
77
|
+
=== Queue configuration for multiple enqueue operations
|
78
|
+
|
79
|
+
Alternatively, the queue may be attached to the job upfront for multiple enqueue operations:
|
80
|
+
|
81
|
+
FooSender.job_queue('high-priority')
|
82
|
+
f1 = FooSender.new(:target => 'cookie monster', :foo_content => 'cookies and milk')
|
83
|
+
f1.enqueue # high-priority queue will be used
|
84
|
+
f2 = FooSender.new(:target => 'oscar the grouch', :foo_content => 'pizza')
|
85
|
+
f2.enqueue # high-priority queue will be used
|
86
|
+
|
87
|
+
|
88
|
+
== Job Server Usage
|
89
|
+
|
90
|
+
Calling #poll on a queue instance will, by default, dispatch each job to the proper registered class based on type and version. Its options are passed through to the underlying implementation. In the case of the SQSJobQueue, poll accepts the options documented for the aws-sdk AWS::SQS::Queue#poll method.
|
91
|
+
|
92
|
+
JobQueue.default.poll(:poll_interval => 1, :idle_timeout => 60)
|
93
|
+
|
94
|
+
You can override the default behavior by passing a block to #poll that accepts both a job definition instance and an SQS message.
|
95
|
+
|
96
|
+
JobQueue.default.poll(:poll_interval => 1, :idle_timeout => 60) do |definition, message|
|
97
|
+
logger.debug "received message: #{message.inspect}"
|
98
|
+
logger.debug "dispatched to definition #{definition.inspect}; executing..."
|
99
|
+
definition.execute
|
100
|
+
end
|
101
|
+
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
|
4
|
+
module SimpleJob
|
5
|
+
module JobDefinition
|
6
|
+
|
7
|
+
RESERVED_ATTRIBUTES = [ :type, :version, :data ]
|
8
|
+
|
9
|
+
def self.included(klass)
|
10
|
+
|
11
|
+
klass.extend(ClassMethods)
|
12
|
+
|
13
|
+
klass.class_eval do
|
14
|
+
include ::ActiveModel::Validations
|
15
|
+
include ::ActiveModel::Serializers::JSON
|
16
|
+
end
|
17
|
+
|
18
|
+
klass.include_root_in_json = false
|
19
|
+
klass.register_simple_job
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
# should be overridden by including classes
|
24
|
+
if !method_defined?(:execute)
|
25
|
+
def execute
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def attributes
|
30
|
+
{
|
31
|
+
'type' => type,
|
32
|
+
'version' => version,
|
33
|
+
'data' => data,
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def attributes=(attributes)
|
38
|
+
attributes.each do |key, value|
|
39
|
+
send("#{key}=", value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def data
|
44
|
+
@data ||= {}
|
45
|
+
self.class.simple_job_attributes.each do |attribute|
|
46
|
+
@data[attribute.to_s] ||= nil
|
47
|
+
end
|
48
|
+
@data
|
49
|
+
end
|
50
|
+
|
51
|
+
def data=(data)
|
52
|
+
self.attributes = data
|
53
|
+
end
|
54
|
+
|
55
|
+
def type
|
56
|
+
self.class.definition[:type]
|
57
|
+
end
|
58
|
+
|
59
|
+
def type=(type)
|
60
|
+
if type.to_sym != self.type
|
61
|
+
raise "tried to deserialize object with type #{type}, but this object only " +
|
62
|
+
"supports type: #{self.type}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def versions
|
67
|
+
self.class.definition[:versions]
|
68
|
+
end
|
69
|
+
|
70
|
+
def version
|
71
|
+
versions.first
|
72
|
+
end
|
73
|
+
|
74
|
+
def version=(version)
|
75
|
+
if !versions.include?(version.to_s)
|
76
|
+
raise "tried to deserialize object with version #{version}, but this object " +
|
77
|
+
"only supports versions: #{versions.join(", ")}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def enqueue(queue_type = nil)
|
82
|
+
if valid?
|
83
|
+
queue = (queue_type && JobQueue[queue_type]) || self.class.job_queue || JobQueue.default
|
84
|
+
queue.enqueue(self.to_json)
|
85
|
+
else
|
86
|
+
false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def enqueue!(queue_type = nil)
|
91
|
+
enqueue(queue_type) || raise("object is not valid: #{errors.full_messages.join('; ')}")
|
92
|
+
end
|
93
|
+
|
94
|
+
def read_simple_job_attribute(attribute)
|
95
|
+
data[attribute.to_s]
|
96
|
+
end
|
97
|
+
|
98
|
+
def write_simple_job_attribute(attribute, value)
|
99
|
+
data[attribute.to_s] = value
|
100
|
+
end
|
101
|
+
|
102
|
+
def initialize(attributes = {})
|
103
|
+
attributes.each do |key, value|
|
104
|
+
send("#{key}=", value)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.job_definition_class_for(type, version)
|
109
|
+
@job_definitions.each do |definition|
|
110
|
+
if (definition[:type] == type.to_sym) && (definition[:versions].include?(version))
|
111
|
+
return definition[:class]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.job_definitions
|
118
|
+
@job_definitions ||= []
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
module ClassMethods
|
124
|
+
|
125
|
+
def definition
|
126
|
+
@definition
|
127
|
+
end
|
128
|
+
|
129
|
+
def register_simple_job(options = {})
|
130
|
+
default_type = self.name.underscore.to_sym
|
131
|
+
|
132
|
+
@definition = {
|
133
|
+
:class => self,
|
134
|
+
:type => default_type,
|
135
|
+
:versions => [ '1' ],
|
136
|
+
}.merge(options)
|
137
|
+
|
138
|
+
@definition[:type] = @definition[:type].to_sym
|
139
|
+
@definition[:versions] = Array(@definition[:versions])
|
140
|
+
@definition[:versions].collect! { |value| value.to_s }
|
141
|
+
|
142
|
+
::SimpleJob::JobDefinition.job_definitions.delete_if { |item| item[:type] == default_type }
|
143
|
+
::SimpleJob::JobDefinition.job_definitions << @definition
|
144
|
+
end
|
145
|
+
|
146
|
+
def job_queue(queue_type = nil)
|
147
|
+
@job_queue = JobQueue[queue_type] if queue_type
|
148
|
+
@job_queue
|
149
|
+
end
|
150
|
+
|
151
|
+
def simple_job_attributes
|
152
|
+
@simple_job_attributes ||= []
|
153
|
+
end
|
154
|
+
|
155
|
+
def simple_job_attribute(*attributes)
|
156
|
+
attributes.each do |attribute|
|
157
|
+
attribute = attribute.to_sym
|
158
|
+
|
159
|
+
if RESERVED_ATTRIBUTES.include?(attribute)
|
160
|
+
raise "attempted to declare reserved attribute: #{attribute}"
|
161
|
+
end
|
162
|
+
|
163
|
+
simple_job_attributes << attribute
|
164
|
+
|
165
|
+
class_eval <<-__EOF__
|
166
|
+
def #{attribute}
|
167
|
+
read_simple_job_attribute(:#{attribute})
|
168
|
+
end
|
169
|
+
|
170
|
+
def #{attribute}=(value)
|
171
|
+
write_simple_job_attribute(:#{attribute}, value)
|
172
|
+
end
|
173
|
+
__EOF__
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'aws-sdk'
|
3
|
+
|
4
|
+
# Requires the aws-sdk gem, which must be initialized for this API to be capable of queuing requests.
|
5
|
+
#
|
6
|
+
# Synopsis:
|
7
|
+
#
|
8
|
+
# include SimpleJob
|
9
|
+
#
|
10
|
+
# JobQueue::DEFAULT.poll do |message|
|
11
|
+
# puts message
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# == Creating a queue implementation
|
15
|
+
#
|
16
|
+
# To create a new queue implementation, just extend the SimpleJob::JobQueue
|
17
|
+
# class, and call the register_job_queue declaration with an identifier. The
|
18
|
+
# class must implement the get_queue class method and the enqueue/poll instance
|
19
|
+
# methods to fulfill the interface. The default_queue method may be overridden
|
20
|
+
# to set a default queue.
|
21
|
+
#
|
22
|
+
# Example:
|
23
|
+
#
|
24
|
+
# class ArrayQueue < SimpleJob::JobQueue
|
25
|
+
# register_job_queue 'array', self
|
26
|
+
#
|
27
|
+
# include Singleton
|
28
|
+
# default self.instance
|
29
|
+
#
|
30
|
+
# def self.get_queue(type, options = {})
|
31
|
+
# instance
|
32
|
+
# end
|
33
|
+
# def enqueue(message, options = {})
|
34
|
+
# queue << message
|
35
|
+
# end
|
36
|
+
# def poll(options = {}, &block)
|
37
|
+
# options = {
|
38
|
+
# :interval => 1
|
39
|
+
# }.merge(options)
|
40
|
+
# loop do
|
41
|
+
# message = queue.shift
|
42
|
+
# yield(message) if message
|
43
|
+
# Kernel.sleep(options[:interval])
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
# private
|
47
|
+
# def queue
|
48
|
+
# @queue ||= []
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# Then you can use the new queue implementation by passing its identifier to
|
53
|
+
# JobQueue.config:
|
54
|
+
#
|
55
|
+
# SimpleJob::JobQueue.config :implementation => 'array'
|
56
|
+
module SimpleJob
|
57
|
+
class JobQueue
|
58
|
+
|
59
|
+
def self.register_job_queue(identifier, klass)
|
60
|
+
@@registered_job_queues ||= {}
|
61
|
+
@@registered_job_queues[identifier.to_s] = klass
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.config(options = {})
|
65
|
+
@config ||= {
|
66
|
+
:implementation => 'sqs',
|
67
|
+
:logger => default_logger,
|
68
|
+
}
|
69
|
+
@config.merge!(options) if options
|
70
|
+
@config
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.[](type, options = {})
|
74
|
+
queue_class.get_queue(type, options)
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.default_queue
|
78
|
+
raise "default queue not defined"
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.default
|
82
|
+
queue_class.default_queue
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.get_queue(type, options = {})
|
86
|
+
raise "queue with type #{type} not defined"
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.queue_class
|
90
|
+
@@registered_job_queues[config[:implementation].to_s]
|
91
|
+
end
|
92
|
+
|
93
|
+
def enqueue(message, options = {})
|
94
|
+
raise NotImplementedError
|
95
|
+
end
|
96
|
+
|
97
|
+
def poll(options = {}, &block)
|
98
|
+
raise NotImplementedError
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def self.default_logger
|
104
|
+
return Rails.logger if defined?(Rails)
|
105
|
+
logger = Logger.new(STDERR)
|
106
|
+
logger.level = Logger::INFO
|
107
|
+
logger
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module SimpleJob
|
2
|
+
class SQSJobQueue < JobQueue
|
3
|
+
|
4
|
+
# Registers this queue implementation with SimpleJob::JobQueue with identifier "sqs".
|
5
|
+
register_job_queue 'sqs', self
|
6
|
+
|
7
|
+
def self.config(options = {})
|
8
|
+
@config ||= {
|
9
|
+
:queue_prefix => ENV['SIMPLE_JOB_SQS_JOB_QUEUE_PREFIX'],
|
10
|
+
:default_visibility_timeout => 60,
|
11
|
+
:environment => (defined?(Rails) && Rails.env) || 'development',
|
12
|
+
}
|
13
|
+
|
14
|
+
@config.merge!(options) if options
|
15
|
+
|
16
|
+
raise 'must configure :queue_prefix using SQSJobQueue.config' if !@config[:queue_prefix]
|
17
|
+
|
18
|
+
@config
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.default_queue
|
22
|
+
@default_queue || super
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.define_queue(type, options = {})
|
26
|
+
type = type.to_s
|
27
|
+
|
28
|
+
options = {
|
29
|
+
:visibility_timeout => config[:default_visibility_timeout],
|
30
|
+
:default => false,
|
31
|
+
}.merge(options)
|
32
|
+
|
33
|
+
queue = self.new(type, options[:visibility_timeout])
|
34
|
+
self.queues ||= {}
|
35
|
+
self.queues[type] = queue
|
36
|
+
|
37
|
+
@default_queue = queue if options[:default]
|
38
|
+
|
39
|
+
queue
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.get_queue(type, options = {})
|
43
|
+
type = type.to_s
|
44
|
+
(self.queues || {})[type] || super
|
45
|
+
end
|
46
|
+
|
47
|
+
def enqueue(message, options = {})
|
48
|
+
raise("enqueue expects a raw string") unless message.is_a?(String)
|
49
|
+
sqs_queue.send_message(message)
|
50
|
+
end
|
51
|
+
|
52
|
+
def poll(options = {}, &block)
|
53
|
+
options = {
|
54
|
+
:visibility_timeout => visibility_timeout,
|
55
|
+
:attributes => [ :sent_at, :receive_count, :first_received_at ],
|
56
|
+
:raise_exceptions => false,
|
57
|
+
}.merge(options)
|
58
|
+
|
59
|
+
message_handler = block || lambda do |definition, message|
|
60
|
+
definition.execute
|
61
|
+
end
|
62
|
+
|
63
|
+
sqs_queue.poll(options) do |message|
|
64
|
+
begin
|
65
|
+
raw_message = JSON.parse(message.body)
|
66
|
+
definition_class = JobDefinition.job_definition_class_for(raw_message['type'], raw_message['version'])
|
67
|
+
raise('no definition found') if !definition_class
|
68
|
+
definition = definition_class.new.from_json(message.body)
|
69
|
+
message_handler.call(definition, message)
|
70
|
+
rescue Exception => e
|
71
|
+
if options[:raise_exceptions]
|
72
|
+
raise e
|
73
|
+
else
|
74
|
+
JobQueue.config[:logger].error("unable to process message: #{e.message}")
|
75
|
+
JobQueue.config[:logger].error("message body: #{message.body}")
|
76
|
+
JobQueue.config[:logger].error(e.backtrace.join("\n "))
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
class << self
|
85
|
+
attr_accessor :queues
|
86
|
+
end
|
87
|
+
|
88
|
+
attr_accessor :sqs_queue, :visibility_timeout
|
89
|
+
|
90
|
+
def initialize(type, visibility_timeout)
|
91
|
+
sqs = ::AWS::SQS.new
|
92
|
+
self.sqs_queue = sqs.queues.create "#{self.class.config[:queue_prefix]}-#{type}-#{self.class.config[:environment]}"
|
93
|
+
self.visibility_timeout = visibility_timeout
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
data/lib/simple_job.rb
ADDED
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simple_job
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- David Dawson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-10 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activemodel
|
16
|
+
requirement: &70245578980360 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70245578980360
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
requirement: &70245578978120 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3.0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70245578978120
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: aws-sdk
|
38
|
+
requirement: &70245578976320 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.2'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70245578976320
|
47
|
+
description: Contains libraries that support defining, queueing, and executing jobs.
|
48
|
+
email: daws23@gmail.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README.rdoc
|
53
|
+
- CHANGELOG.rdoc
|
54
|
+
- LICENSE.txt
|
55
|
+
files:
|
56
|
+
- lib/simple_job/job_definition.rb
|
57
|
+
- lib/simple_job/job_queue.rb
|
58
|
+
- lib/simple_job/sqs_job_queue.rb
|
59
|
+
- lib/simple_job/version.rb
|
60
|
+
- lib/simple_job.rb
|
61
|
+
- README.rdoc
|
62
|
+
- CHANGELOG.rdoc
|
63
|
+
- LICENSE.txt
|
64
|
+
homepage: https://github.com/daws/simple_job
|
65
|
+
licenses: []
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options:
|
68
|
+
- --main
|
69
|
+
- README.rdoc
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
segments:
|
79
|
+
- 0
|
80
|
+
hash: -2274642139086505235
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
requirements: []
|
88
|
+
rubyforge_project:
|
89
|
+
rubygems_version: 1.8.10
|
90
|
+
signing_key:
|
91
|
+
specification_version: 3
|
92
|
+
summary: Support classes and modules for executable jobs.
|
93
|
+
test_files: []
|