simple_worker 2.0.0.beta.11 → 2.0.0.beta.15
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +9 -3
- data/lib/simple_worker/api.rb +67 -11
- data/lib/simple_worker/base.rb +19 -14
- data/lib/simple_worker/service.rb +58 -60
- metadata +13 -2
data/README.markdown
CHANGED
@@ -80,6 +80,14 @@ Let's say someone does something in your app and you want to send an email about
|
|
80
80
|
|
81
81
|
This will send it off to the SimpleWorker cloud.
|
82
82
|
|
83
|
+
To queue worker without uploading you could try to do following:
|
84
|
+
|
85
|
+
data[:attr_encoded] = Base64.encode64({'@to'=>'example@email.com'}.to_json)
|
86
|
+
data[:sw_config] = SimpleWorker.config.get_atts_to_send
|
87
|
+
SimpleWorker.service.queue('EmailWorker', data)
|
88
|
+
|
89
|
+
|
90
|
+
|
83
91
|
Setting Priority
|
84
92
|
----------------------------------------------
|
85
93
|
|
@@ -261,9 +269,7 @@ You could easily merge mailers you're using in your application.
|
|
261
269
|
#or
|
262
270
|
merge_mailer 'mailer_file', {:path_to_templates=>"templates_path"}#if you're using mailer outside of rails with custom templates path
|
263
271
|
|
264
|
-
|
265
|
-
|
266
|
-
Configuring a Mailer Connection
|
272
|
+
### Configuring a Mailer Connection
|
267
273
|
|
268
274
|
If you are using Rails 3,your action_mailer connection would be configured automatically from your config
|
269
275
|
|
data/lib/simple_worker/api.rb
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
require 'rest_client'
|
2
|
+
require 'patron'
|
2
3
|
|
3
4
|
module SimpleWorker
|
5
|
+
|
6
|
+
class RequestError < StandardError
|
7
|
+
def initialize(msg, options={})
|
8
|
+
super(msg)
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def status
|
13
|
+
@options[:status]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
4
17
|
module Api
|
5
18
|
|
6
19
|
module Signatures
|
@@ -30,7 +43,7 @@ module SimpleWorker
|
|
30
43
|
# host: endpoint url for service
|
31
44
|
class Client
|
32
45
|
|
33
|
-
attr_accessor :host, :port, :token, :version, :config
|
46
|
+
attr_accessor :scheme, :host, :port, :token, :version, :config
|
34
47
|
|
35
48
|
def initialize(host, token, options={})
|
36
49
|
@config = options[:config]
|
@@ -41,10 +54,25 @@ module SimpleWorker
|
|
41
54
|
@version = options[:version]
|
42
55
|
@logger = options[:logger]
|
43
56
|
|
57
|
+
@base_url = "#{@scheme}://#{@host}:#{@port}/#{@version}"
|
58
|
+
|
59
|
+
sess = Patron::Session.new
|
60
|
+
sess.timeout = 10
|
61
|
+
sess.base_url = @base_url
|
62
|
+
sess.headers['User-Agent'] = 'IronMQ Ruby Client'
|
63
|
+
#sess.enable_debug "/tmp/patron.debug"
|
64
|
+
@http_sess = sess
|
65
|
+
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def base_url
|
71
|
+
@base_url
|
44
72
|
end
|
45
73
|
|
46
74
|
def url(command_path)
|
47
|
-
url = "#{
|
75
|
+
url = "#{base_url}/#{command_path}"
|
48
76
|
# @logger.debug "url: " + url.to_s
|
49
77
|
url
|
50
78
|
end
|
@@ -59,15 +87,32 @@ module SimpleWorker
|
|
59
87
|
raise exception
|
60
88
|
end
|
61
89
|
|
90
|
+
def check_response(response, options={})
|
91
|
+
status = response.status
|
92
|
+
body = response.body
|
93
|
+
res = nil
|
94
|
+
unless options[:parse] == false
|
95
|
+
res = JSON.parse(body)
|
96
|
+
end
|
97
|
+
if status < 400
|
98
|
+
|
99
|
+
else
|
100
|
+
raise SimpleWorker::RequestError.new((res ? "#{status}: #{res["msg"]}" : "#{status} Error! parse=false so no msg"), :status=>status)
|
101
|
+
end
|
102
|
+
res || body
|
103
|
+
end
|
104
|
+
|
62
105
|
def get(method, params={}, options={})
|
63
106
|
full_url = url(method)
|
64
107
|
all_params = add_params(method, params)
|
65
|
-
|
66
108
|
url_plus_params = append_params(full_url, all_params)
|
67
109
|
@logger.debug 'get url=' + url_plus_params
|
68
|
-
|
69
|
-
|
70
|
-
|
110
|
+
response = @http_sess.request(:get, url_plus_params,
|
111
|
+
{},
|
112
|
+
{})
|
113
|
+
check_response(response, options)
|
114
|
+
body = response.body
|
115
|
+
parse_response(body, options)
|
71
116
|
|
72
117
|
end
|
73
118
|
|
@@ -79,9 +124,9 @@ module SimpleWorker
|
|
79
124
|
@logger.debug "data = " + data
|
80
125
|
@logger.debug "params = " + params.inspect
|
81
126
|
@logger.debug "options = " + options.inspect
|
82
|
-
|
83
|
-
|
84
|
-
rescue
|
127
|
+
# todo: replace with patron
|
128
|
+
parse_response(RestClient.post(append_params(url(method), add_params(method, params)), {:data => data, :file => file}, :content_type => 'application/json'), options)
|
129
|
+
rescue Exception => ex
|
85
130
|
process_ex(ex)
|
86
131
|
end
|
87
132
|
end
|
@@ -94,8 +139,17 @@ module SimpleWorker
|
|
94
139
|
begin
|
95
140
|
url = url(method) + "?oauth=" + token
|
96
141
|
@logger.debug 'post url=' + url
|
97
|
-
|
98
|
-
|
142
|
+
json = add_params(method, params).to_json
|
143
|
+
@logger.debug 'body=' + json
|
144
|
+
response = @http_sess.post(url, json, {"Content-Type" => 'application/json'})
|
145
|
+
check_response(response)
|
146
|
+
@logger.debug 'response: ' + response.inspect
|
147
|
+
body = response.body
|
148
|
+
parse_response(body, options)
|
149
|
+
rescue SimpleWorker::RequestError => ex
|
150
|
+
# let it throw, came from check_response
|
151
|
+
raise ex
|
152
|
+
rescue Exception => ex
|
99
153
|
@logger.warn("Exception in post! #{ex.message}")
|
100
154
|
@logger.warn(ex.backtrace.join("\n"))
|
101
155
|
process_ex(ex)
|
@@ -105,6 +159,7 @@ module SimpleWorker
|
|
105
159
|
|
106
160
|
def put(method, body, options={})
|
107
161
|
begin
|
162
|
+
# todo: replace with patron
|
108
163
|
parse_response RestClient.put(url(method), add_params(method, body).to_json, headers), options
|
109
164
|
rescue RestClient::Exception => ex
|
110
165
|
process_ex(ex)
|
@@ -113,6 +168,7 @@ module SimpleWorker
|
|
113
168
|
|
114
169
|
def delete(method, params={}, options={})
|
115
170
|
begin
|
171
|
+
# todo: replace with patron
|
116
172
|
parse_response RestClient.delete(append_params(url(method), add_params(method, params))), options
|
117
173
|
rescue RestClient::Exception => ex
|
118
174
|
process_ex(ex)
|
data/lib/simple_worker/base.rb
CHANGED
@@ -41,11 +41,16 @@ module SimpleWorker
|
|
41
41
|
def merge_gem(gem_name, options={})
|
42
42
|
gem_info = SimpleWorker::MergeHelper.create_gem_info(gem_name, options)
|
43
43
|
@merged_gems[gem_name.to_s] = gem_info
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
44
|
+
reqs = gem_info[:require].is_a?(Array) ? gem_info[:require] : [gem_info[:require]]
|
45
|
+
reqs.each do |r|
|
46
|
+
r2 = "#{gem_info[:path]}/lib/#{r}"
|
47
|
+
begin
|
48
|
+
puts 'requiring ' + r2
|
49
|
+
require r2
|
50
|
+
rescue LoadError=>ex
|
51
|
+
SimpleWorker.logger.error "Error requiring gem #{r}: #{ex.message}"
|
52
|
+
raise "Gem #{gem_name} was found, but we could not load the file '#{r2}'. You may need to use :require=>x.........."
|
53
|
+
end
|
49
54
|
end
|
50
55
|
end
|
51
56
|
|
@@ -151,7 +156,7 @@ module SimpleWorker
|
|
151
156
|
# puts 'run_local'
|
152
157
|
set_auto_attributes
|
153
158
|
init_database
|
154
|
-
|
159
|
+
init_mailer
|
155
160
|
begin
|
156
161
|
run
|
157
162
|
rescue => ex
|
@@ -163,11 +168,11 @@ module SimpleWorker
|
|
163
168
|
end
|
164
169
|
end
|
165
170
|
|
166
|
-
|
171
|
+
def init_mailer
|
167
172
|
if SimpleWorker.config.mailer
|
168
173
|
require 'action_mailer'
|
169
|
-
|
170
|
-
|
174
|
+
ActionMailer::Base.raise_delivery_errors = true
|
175
|
+
ActionMailer::Base.smtp_settings = (SimpleWorker.config.mailer)
|
171
176
|
end
|
172
177
|
end
|
173
178
|
|
@@ -212,9 +217,8 @@ module SimpleWorker
|
|
212
217
|
upload_if_needed(options)
|
213
218
|
|
214
219
|
response = SimpleWorker.service.queue(self.class.name, sw_get_data, options)
|
215
|
-
|
216
|
-
|
217
|
-
@task_id = response["task_id"]
|
220
|
+
SimpleWorker.service.logger.debug 'queue response=' + response.inspect
|
221
|
+
@task_id = response["tasks"][0]["id"]
|
218
222
|
response
|
219
223
|
end
|
220
224
|
|
@@ -270,8 +274,8 @@ module SimpleWorker
|
|
270
274
|
upload_if_needed(schedule)
|
271
275
|
|
272
276
|
response = SimpleWorker.service.schedule(self.class.name, sw_get_data, schedule)
|
273
|
-
|
274
|
-
@schedule_id = response["
|
277
|
+
SimpleWorker.service.logger.debug 'schedule response=' + response.inspect
|
278
|
+
@schedule_id = response["schedules"][0]["id"]
|
275
279
|
response
|
276
280
|
end
|
277
281
|
|
@@ -408,6 +412,7 @@ module SimpleWorker
|
|
408
412
|
self.instance_variables.each do |iv|
|
409
413
|
payload[iv] = instance_variable_get(iv)
|
410
414
|
end
|
415
|
+
data['class_name'] = self.class.name
|
411
416
|
data[:attr_encoded] = Base64.encode64(payload.to_json)
|
412
417
|
data[:file_name] = File.basename(self.class.instance_variable_get(:@caller_file))
|
413
418
|
if defined?(Rails)
|
@@ -22,9 +22,11 @@ module SimpleWorker
|
|
22
22
|
end
|
23
23
|
options[:version] = SimpleWorker.api_version
|
24
24
|
options[:logger] = SimpleWorker.logger
|
25
|
-
super("
|
25
|
+
super("worker-aws-us-east-1.iron.io", token, options)
|
26
26
|
self.host = self.config.host if self.config && self.config.host
|
27
|
-
|
27
|
+
# automerge simple worker gem and dependenices
|
28
|
+
self.config.merge_gem('rest-client')
|
29
|
+
self.config.merge_gem('simple_worker')
|
28
30
|
SimpleWorker.logger.info 'SimpleWorker initialized.'
|
29
31
|
SimpleWorker.logger.debug ' host = ' + self.host.inspect
|
30
32
|
end
|
@@ -35,8 +37,6 @@ module SimpleWorker
|
|
35
37
|
def upload(filename, class_name, options={})
|
36
38
|
name = options[:name] || class_name
|
37
39
|
project_id = get_project_id(options)
|
38
|
-
# puts "Uploading #{class_name}"
|
39
|
-
# check whether it should upload again
|
40
40
|
tmp = Dir.tmpdir()
|
41
41
|
md5file = "simple_worker_#{class_name.gsub("::", ".")}_#{token[0, 8]}.md5"
|
42
42
|
existing_md5 = nil
|
@@ -44,7 +44,7 @@ module SimpleWorker
|
|
44
44
|
if File.exists?(md5_f)
|
45
45
|
existing_md5 = IO.read(md5_f)
|
46
46
|
end
|
47
|
-
# Check for code changes.
|
47
|
+
# Check for code changes.
|
48
48
|
md5 = Digest::MD5.hexdigest(File.read(filename))
|
49
49
|
new_code = false
|
50
50
|
if self.config.force_upload || md5 != existing_md5
|
@@ -125,12 +125,8 @@ module SimpleWorker
|
|
125
125
|
#tmp_file = File.join(Dir.tmpdir(), File.basename(filename))
|
126
126
|
tmp_file = File.join(Dir.tmpdir(), 'runner.rb')
|
127
127
|
File.open(tmp_file, "w") do |f|
|
128
|
-
|
129
|
-
|
130
|
-
f.write line
|
131
|
-
end
|
132
|
-
end
|
133
|
-
f.write("begin\n")#error handling block start
|
128
|
+
|
129
|
+
f.write("begin\n") #error handling block start
|
134
130
|
f.write("
|
135
131
|
# Find environment (-e)
|
136
132
|
dirname = ''
|
@@ -155,13 +151,13 @@ ARGV.each do |arg|
|
|
155
151
|
end
|
156
152
|
require 'json'
|
157
153
|
")
|
158
|
-
|
159
|
-
|
154
|
+
# require merged gems
|
155
|
+
merged_gems.each_pair do |k, gem|
|
160
156
|
SimpleWorker.logger.debug "Bundling gem #{gem[:name]}..."
|
161
157
|
if gem[:merge]
|
162
158
|
f.write "$LOAD_PATH << File.join(File.dirname(__FILE__), '/gems/#{gem[:name]}/lib')\n"
|
163
159
|
end
|
164
|
-
# unless gem[:no_require]
|
160
|
+
# unless gem[:no_require]
|
165
161
|
SimpleWorker.logger.debug 'writing requires: ' + gem[:require].inspect
|
166
162
|
if gem[:require].nil?
|
167
163
|
gem[:require] = []
|
@@ -173,11 +169,17 @@ require 'json'
|
|
173
169
|
SimpleWorker.logger.debug 'adding require to file ' + r.to_s
|
174
170
|
f.write "require '#{r}'\n"
|
175
171
|
end
|
176
|
-
|
177
|
-
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
File.open(File.join(File.dirname(__FILE__), "server", 'runner.rb'), 'r') do |fr|
|
176
|
+
while line = fr.gets
|
177
|
+
f.write line
|
178
|
+
end
|
179
|
+
end
|
178
180
|
|
179
181
|
# load job data
|
180
|
-
f.write("
|
182
|
+
f.write("
|
181
183
|
# Change to user directory
|
182
184
|
#puts 'dirname=' + dirname.inspect
|
183
185
|
Dir.chdir(dirname)
|
@@ -185,11 +187,8 @@ Dir.chdir(dirname)
|
|
185
187
|
job_data = JSON.load(File.open(task_data_file))
|
186
188
|
puts 'job_data=' + job_data.inspect
|
187
189
|
sw_config = job_data['sw_config']
|
188
|
-
init_database_connection(sw_config)
|
189
|
-
init_mailer(sw_config)
|
190
190
|
")
|
191
191
|
|
192
|
-
f.write("require 'simple_worker'\n")
|
193
192
|
|
194
193
|
# add some rails stuff if using Rails
|
195
194
|
if defined?(Rails)
|
@@ -204,22 +203,18 @@ end
|
|
204
203
|
"
|
205
204
|
end
|
206
205
|
|
207
|
-
if SimpleWorker.config.
|
208
|
-
|
206
|
+
if SimpleWorker.config.extra_requires
|
207
|
+
SimpleWorker.config.extra_requires.each do |r|
|
208
|
+
f.write "require '#{r}'\n"
|
209
|
+
end
|
209
210
|
end
|
210
|
-
|
211
211
|
if merged_mailers && !merged_mailers.empty?
|
212
212
|
# todo: isn't 'action_mailer already required in railtie?
|
213
213
|
f.write "require 'action_mailer'\n"
|
214
|
+
f.write "init_mailer(sw_config)\n"
|
214
215
|
f.write "ActionMailer::Base.prepend_view_path('templates')\n"
|
215
216
|
end
|
216
|
-
|
217
|
-
|
218
|
-
if SimpleWorker.config.extra_requires
|
219
|
-
SimpleWorker.config.extra_requires.each do |r|
|
220
|
-
f.write "require '#{r}'\n"
|
221
|
-
end
|
222
|
-
end
|
217
|
+
f.write "init_database_connection(sw_config)"
|
223
218
|
|
224
219
|
File.open(File.join(File.dirname(__FILE__), 'server', 'overrides.rb'), 'r') do |fr|
|
225
220
|
while line = fr.gets
|
@@ -239,8 +234,6 @@ end
|
|
239
234
|
#f.write File.open(filename, 'r') { |mo| mo.read }
|
240
235
|
f.write("require_relative '#{File.basename(filename)}'")
|
241
236
|
|
242
|
-
|
243
|
-
|
244
237
|
f.write("
|
245
238
|
SimpleWorker.disable_queueing()
|
246
239
|
runner_class = get_class_to_run(job_data['class_name'])
|
@@ -381,7 +374,7 @@ end
|
|
381
374
|
"projects/#{project_id}/"
|
382
375
|
end
|
383
376
|
|
384
|
-
def wait_until_complete(task_id)
|
377
|
+
def wait_until_complete(task_id, options={})
|
385
378
|
tries = 0
|
386
379
|
status = nil
|
387
380
|
sleep 1
|
@@ -398,7 +391,7 @@ end
|
|
398
391
|
|
399
392
|
def add_sw_params(hash_to_send)
|
400
393
|
# todo: remove secret key?? Can use worker service from within a worker without it now
|
401
|
-
hash_to_send["
|
394
|
+
hash_to_send["oauth"] = self.token
|
402
395
|
hash_to_send["api_version"] = SimpleWorker.api_version
|
403
396
|
end
|
404
397
|
|
@@ -408,42 +401,46 @@ end
|
|
408
401
|
end
|
409
402
|
end
|
410
403
|
|
411
|
-
def enqueue(
|
412
|
-
queue(
|
404
|
+
def enqueue(name, data={}, options={})
|
405
|
+
queue(name, data, options)
|
413
406
|
end
|
414
407
|
|
415
|
-
#
|
408
|
+
# name: The name of previously upload worker code, eg: MySuperWorker
|
416
409
|
# data: Arbitrary hash of your own data that your task will need to run.
|
417
|
-
def queue(
|
418
|
-
puts "Queuing #{
|
410
|
+
def queue(name, data={}, options={})
|
411
|
+
puts "Queuing #{name}..."
|
419
412
|
check_config
|
420
413
|
if !data.is_a?(Array)
|
421
414
|
data = [data]
|
422
415
|
end
|
423
416
|
# Now we need to add class_name to the payload
|
417
|
+
tasks = []
|
424
418
|
data.each do |d|
|
425
|
-
d['class_name'] = class_name
|
419
|
+
d['class_name'] = name unless d['class_name']
|
420
|
+
task = {}
|
421
|
+
task["payload"] = d.to_json
|
422
|
+
task["code_name"] = name
|
423
|
+
task["priority"] = options[:priority] if options[:priority]
|
424
|
+
task["timeout"] = options[:timeout] if options[:timeout]
|
425
|
+
tasks << task
|
426
426
|
end
|
427
|
-
name = options[:name] ||
|
427
|
+
name = options[:name] || name
|
428
428
|
hash_to_send = {}
|
429
|
-
hash_to_send["payload"] = data
|
430
|
-
hash_to_send["class_name"] = class_name
|
431
|
-
hash_to_send["name"] = name
|
432
|
-
hash_to_send["priority"] = options[:priority] if options[:priority]
|
433
429
|
hash_to_send["options"] = options
|
430
|
+
hash_to_send["tasks"] = tasks
|
434
431
|
add_sw_params(hash_to_send)
|
435
432
|
if defined?(RAILS_ENV)
|
436
433
|
# todo: REMOVE THIS
|
437
434
|
hash_to_send["rails_env"] = RAILS_ENV
|
438
435
|
end
|
439
|
-
return queue_raw(
|
436
|
+
return queue_raw(name, hash_to_send, options)
|
440
437
|
end
|
441
438
|
|
442
|
-
def queue_raw(
|
439
|
+
def queue_raw(name, data={}, options={})
|
443
440
|
params = nil
|
444
441
|
hash_to_send = data
|
445
|
-
hash_to_send["class_name"] =
|
446
|
-
hash_to_send["name"] =
|
442
|
+
#hash_to_send["class_name"] = name unless hash_to_send["class_name"]
|
443
|
+
hash_to_send["name"] = name unless hash_to_send["name"]
|
447
444
|
uri = project_url_prefix(get_project_id(options)) + "tasks"
|
448
445
|
SimpleWorker.logger.debug 'queue_raw , uri = ' + uri
|
449
446
|
ret = post(uri, hash_to_send)
|
@@ -460,19 +457,20 @@ end
|
|
460
457
|
# - end_at: Scheduled task will stop running after this date (optional, if ommitted, runs forever or until cancelled)
|
461
458
|
# - run_times: Task will run exactly :run_times. For instance if :run_times is 5, then the task will run 5 times.
|
462
459
|
#
|
463
|
-
def schedule(
|
464
|
-
puts "Scheduling #{
|
460
|
+
def schedule(name, data, schedule)
|
461
|
+
puts "Scheduling #{name}..."
|
465
462
|
raise "Schedule must be a hash." if !schedule.is_a? Hash
|
466
|
-
# if !data.is_a?(Array)
|
467
|
-
# data = [data]
|
468
|
-
# end
|
469
463
|
hash_to_send = {}
|
470
|
-
|
471
|
-
|
472
|
-
|
464
|
+
schedules = []
|
465
|
+
schedule["payload"] = data.to_json
|
466
|
+
schedule["name"] = name unless schedule["name"]
|
467
|
+
schedule["code_name"] = name unless schedule["code_name"]
|
468
|
+
schedules << schedule
|
469
|
+
hash_to_send["schedules"] = schedules
|
473
470
|
add_sw_params(hash_to_send)
|
474
471
|
# puts ' about to send ' + hash_to_send.inspect
|
475
|
-
|
472
|
+
uri = project_url_prefix(get_project_id(data)) + "schedules"
|
473
|
+
ret = post(uri, hash_to_send)
|
476
474
|
ret
|
477
475
|
end
|
478
476
|
|
@@ -542,9 +540,9 @@ end
|
|
542
540
|
ret
|
543
541
|
end
|
544
542
|
|
545
|
-
def schedule_status(schedule_id)
|
543
|
+
def schedule_status(schedule_id, options={})
|
546
544
|
data = {"schedule_id"=>schedule_id}
|
547
|
-
ret = get("
|
545
|
+
ret = get("#{project_url_prefix(get_project_id(options))}schedules/#{schedule_id}", data)
|
548
546
|
ret
|
549
547
|
end
|
550
548
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: simple_worker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: 6
|
5
|
-
version: 2.0.0.beta.
|
5
|
+
version: 2.0.0.beta.15
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Travis Reeder
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-10-
|
13
|
+
date: 2011-10-27 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: zip
|
@@ -34,6 +34,17 @@ dependencies:
|
|
34
34
|
version: "0"
|
35
35
|
type: :runtime
|
36
36
|
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: patron
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id003
|
37
48
|
description: The official SimpleWorker gem for http://www.simpleworker.com
|
38
49
|
email: travis@appoxy.com
|
39
50
|
executables: []
|