iron_mq 5.0.1 → 6.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile.lock +19 -17
- data/README.md +420 -70
- data/iron_mq.gemspec +2 -1
- data/lib/iron_mq/client.rb +38 -14
- data/lib/iron_mq/messages.rb +22 -8
- data/lib/iron_mq/queues.rb +105 -66
- data/lib/iron_mq/response.rb +2 -2
- data/lib/iron_mq/subscribers.rb +7 -2
- data/lib/iron_mq/version.rb +1 -1
- data/test/Rakefile +33 -0
- data/test/quick_run.rb +4 -4
- data/test/quick_run2.rb +2 -2
- data/test/test_alerts.rb +79 -32
- data/test/test_base.rb +6 -4
- data/test/test_bulk.rb +1 -1
- data/test/test_iron_mq.rb +183 -141
- data/test/test_mq_worker_subscribers.rb +2 -2
- data/test/test_performance.rb +29 -0
- data/test/test_push_queues.rb +85 -116
- data/test/tmp.rb +2 -0
- metadata +48 -32
- data/test/test_beanstalkd.rb +0 -243
data/iron_mq.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |gem|
|
|
20
20
|
gem.add_runtime_dependency "iron_core", ">= 0.5.1"
|
21
21
|
|
22
22
|
gem.add_development_dependency "test-unit"
|
23
|
-
gem.add_development_dependency "minitest"
|
23
|
+
gem.add_development_dependency "minitest", ">= 5.0"
|
24
24
|
gem.add_development_dependency "rake"
|
25
25
|
gem.add_development_dependency "beanstalk-client"
|
26
26
|
gem.add_development_dependency "uber_config"
|
@@ -29,5 +29,6 @@ Gem::Specification.new do |gem|
|
|
29
29
|
gem.add_development_dependency "quicky"
|
30
30
|
gem.add_development_dependency "iron_worker_ng"
|
31
31
|
gem.add_development_dependency "go"
|
32
|
+
gem.add_development_dependency "parallel"
|
32
33
|
end
|
33
34
|
|
data/lib/iron_mq/client.rb
CHANGED
@@ -11,40 +11,47 @@ module IronMQ
|
|
11
11
|
|
12
12
|
def initialize(options={})
|
13
13
|
default_options = {
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
18
|
-
:
|
14
|
+
scheme: 'https',
|
15
|
+
host: IronMQ::Client::AWS_US_EAST_HOST,
|
16
|
+
port: 443,
|
17
|
+
api_version: 3,
|
18
|
+
user_agent: 'iron_mq_ruby-' + IronMQ::VERSION +
|
19
|
+
' (iron_core_ruby-' + IronCore.version + ')'
|
19
20
|
}
|
20
21
|
|
21
|
-
super('iron', 'mq', options, default_options,
|
22
|
+
super('iron', 'mq', options, default_options,
|
23
|
+
[:project_id, :token, :api_version])
|
22
24
|
|
23
|
-
|
25
|
+
if @keystone.nil?
|
26
|
+
if @token.nil?
|
27
|
+
IronCore::Logger.error 'IronMQ', 'Token is not set', IronCore::Error
|
28
|
+
end
|
24
29
|
|
25
|
-
|
30
|
+
check_id(@project_id, 'project_id')
|
31
|
+
end
|
26
32
|
|
27
33
|
@logger = Logger.new(STDOUT)
|
28
34
|
@logger.level = Logger::INFO
|
29
35
|
end
|
30
36
|
|
31
37
|
def headers
|
32
|
-
super.merge({'Authorization' => "OAuth #{@token}"})
|
38
|
+
super.merge({'Authorization' => "OAuth #{@token_provider.nil? ? @token : @token_provider.token}"})
|
33
39
|
end
|
34
40
|
|
35
41
|
def base_url
|
36
|
-
@base_url
|
42
|
+
@base_url ||= "#{super}#{@api_version}/projects/#{@project_id}/queues"
|
37
43
|
end
|
38
44
|
|
39
45
|
def queues_list(options = {})
|
40
46
|
is_raw = [options.delete(:raw),
|
41
47
|
options.delete('raw')].compact.first
|
42
48
|
response = parse_response(get('', options)) # GET base_url
|
49
|
+
# p response
|
43
50
|
# returns list of evaluated queues
|
44
51
|
if is_raw
|
45
52
|
response.map{ |q_info| ResponseBase.new(q_info) }
|
46
53
|
else
|
47
|
-
response.map{ |q_info| Queue.new(self, q_info[
|
54
|
+
response['queues'].map { |q_info| Queue.new(self, q_info['name']) }
|
48
55
|
end
|
49
56
|
end
|
50
57
|
|
@@ -58,11 +65,11 @@ module IronMQ
|
|
58
65
|
alias_method :queue, :queues_get
|
59
66
|
|
60
67
|
# Backward compatibility for
|
61
|
-
# client.queues.get(:
|
62
|
-
# client.queues.get(
|
68
|
+
# client.queues.get(name: 'my_queue')
|
69
|
+
# client.queues.get('name' => 'my_queue')
|
63
70
|
def get(*args)
|
64
71
|
if args.size == 1 && args[0].is_a?(Hash)
|
65
|
-
queue_name = (args[0][:name] || args[0][
|
72
|
+
queue_name = (args[0][:name] || args[0]['name']).to_s
|
66
73
|
queue_name.empty? ? super : queues_get(queue_name)
|
67
74
|
else
|
68
75
|
super
|
@@ -76,6 +83,23 @@ module IronMQ
|
|
76
83
|
def queues
|
77
84
|
self
|
78
85
|
end
|
86
|
+
|
87
|
+
def create_queue(queue_name, options)
|
88
|
+
response = self.put("/#{CGI::escape(queue_name).gsub('+', '%20')}",
|
89
|
+
{queue: options})
|
90
|
+
queue_hash = JSON.parse(response.body.to_s)
|
91
|
+
|
92
|
+
ResponseBase.new(queue_hash['queue'])
|
93
|
+
end
|
94
|
+
|
95
|
+
def update_queue(queue_name, options)
|
96
|
+
response = self.patch("/#{CGI::escape(queue_name).gsub('+', '%20')}",
|
97
|
+
{queue: options})
|
98
|
+
queue_hash = JSON.parse(response.body.to_s)
|
99
|
+
|
100
|
+
ResponseBase.new(queue_hash['queue'])
|
101
|
+
end
|
102
|
+
|
79
103
|
end
|
80
104
|
|
81
105
|
end
|
data/lib/iron_mq/messages.rb
CHANGED
@@ -30,17 +30,25 @@ module IronMQ
|
|
30
30
|
@raw['reserved_count']
|
31
31
|
end
|
32
32
|
|
33
|
+
def reservation_id
|
34
|
+
@raw['reservation_id']
|
35
|
+
end
|
36
|
+
|
37
|
+
def push_statuses
|
38
|
+
@raw['push_statuses']
|
39
|
+
end
|
40
|
+
|
33
41
|
def touch
|
34
|
-
call_api_and_parse_response(:post,
|
42
|
+
call_api_and_parse_response(:post, '/touch')
|
35
43
|
end
|
36
44
|
|
37
45
|
def release(options = {})
|
38
|
-
call_api_and_parse_response(:post,
|
46
|
+
call_api_and_parse_response(:post, '/release', options)
|
39
47
|
end
|
40
48
|
|
41
49
|
# `options` was kept for backward compatibility
|
42
50
|
def subscribers(options = {})
|
43
|
-
response = call_api_and_parse_response(:get,
|
51
|
+
response = call_api_and_parse_response(:get, '/subscribers', {}, false)
|
44
52
|
|
45
53
|
response['subscribers'].map { |s| Subscriber.new(s, self, options) }
|
46
54
|
end
|
@@ -49,16 +57,22 @@ module IronMQ
|
|
49
57
|
call_api_and_parse_response(:delete)
|
50
58
|
rescue Rest::HttpError => ex
|
51
59
|
#if ex.code == 404
|
52
|
-
# Rest.logger.info(
|
60
|
+
# Rest.logger.info('Delete got 404, safe to ignore.')
|
53
61
|
# # return ResponseBase as normal
|
54
|
-
# ResponseBase.new({
|
62
|
+
# ResponseBase.new({'msg' => 'Deleted'}, 404)
|
55
63
|
#else
|
56
|
-
|
64
|
+
raise ex
|
57
65
|
#end
|
58
66
|
end
|
59
67
|
|
60
|
-
def call_api_and_parse_response(meth, ext_path =
|
61
|
-
|
68
|
+
def call_api_and_parse_response(meth, ext_path = '',
|
69
|
+
options = {}, instantiate = true)
|
70
|
+
if self.reservation_id && !self.reservation_id.empty?
|
71
|
+
options[:reservation_id] = self.reservation_id
|
72
|
+
end
|
73
|
+
@queue.call_api_and_parse_response(meth,
|
74
|
+
"#{path(ext_path)}",
|
75
|
+
options, instantiate)
|
62
76
|
end
|
63
77
|
|
64
78
|
private
|
data/lib/iron_mq/queues.rb
CHANGED
@@ -18,49 +18,46 @@ module IronMQ
|
|
18
18
|
def load
|
19
19
|
reload if @raw.nil?
|
20
20
|
|
21
|
-
@raw
|
21
|
+
@raw['queue']
|
22
22
|
end
|
23
23
|
|
24
24
|
def reload
|
25
|
-
@raw = call_api_and_parse_response(:get,
|
25
|
+
@raw = call_api_and_parse_response(:get, '', {}, false, true)
|
26
26
|
self
|
27
27
|
end
|
28
28
|
|
29
29
|
def id
|
30
|
-
load
|
31
|
-
@raw['id']
|
30
|
+
load['id']
|
32
31
|
end
|
33
32
|
|
34
33
|
def size
|
35
|
-
load
|
36
|
-
@raw['size'].to_i
|
34
|
+
load['size'].to_i
|
37
35
|
end
|
38
36
|
|
39
37
|
def total_messages
|
40
|
-
load
|
41
|
-
@raw['total_messages'].to_i
|
38
|
+
load['total_messages'].to_i
|
42
39
|
end
|
43
40
|
|
44
|
-
def
|
45
|
-
load
|
46
|
-
@raw['push_type']
|
41
|
+
def type
|
42
|
+
load['type']
|
47
43
|
end
|
48
44
|
|
49
45
|
def push_queue?
|
50
|
-
|
51
|
-
# When the parameter absent it is not guaranted that queue is not push queue.
|
52
|
-
ptype = push_type
|
53
|
-
not (ptype.nil? || ptype.empty?)
|
46
|
+
['multicast', 'unicast'].include?(type)
|
54
47
|
end
|
55
48
|
|
56
|
-
def
|
57
|
-
|
49
|
+
def push_info
|
50
|
+
load['push']
|
51
|
+
end
|
52
|
+
|
53
|
+
def update(options={})
|
54
|
+
call_api_and_parse_response(:put, '', {queue: options})
|
58
55
|
end
|
59
56
|
|
60
57
|
alias_method :update_queue, :update
|
61
58
|
|
62
59
|
def clear
|
63
|
-
call_api_and_parse_response(:
|
60
|
+
call_api_and_parse_response(:delete, '/messages', {}, false, true)
|
64
61
|
end
|
65
62
|
|
66
63
|
alias_method :clear_queue, :clear
|
@@ -72,27 +69,40 @@ module IronMQ
|
|
72
69
|
return r
|
73
70
|
rescue Rest::HttpError => ex
|
74
71
|
#if ex.code == 404
|
75
|
-
# Rest.logger.info(
|
72
|
+
# Rest.logger.info('Delete got 404, safe to ignore.')
|
76
73
|
# # return ResponseBase as normal
|
77
|
-
# ResponseBase.new({
|
74
|
+
# ResponseBase.new({'msg' => 'Deleted'}, 404)
|
78
75
|
#else
|
79
76
|
raise ex
|
80
77
|
#end
|
81
78
|
end
|
82
79
|
|
83
80
|
# Backward compatibility
|
84
|
-
def delete(message_id,
|
81
|
+
def delete(message_id, reservation_id = nil)
|
85
82
|
# API does not accept any options
|
86
|
-
|
83
|
+
options = {}
|
84
|
+
options['id'] = message_id
|
85
|
+
unless reservation_id.nil?
|
86
|
+
options['reservation_id'] = reservation_id
|
87
|
+
end
|
88
|
+
Message.new(self, options).delete
|
87
89
|
end
|
88
90
|
|
89
91
|
# Accepts an array of message ids
|
90
92
|
def delete_messages(ids)
|
91
|
-
call_api_and_parse_response(:delete,
|
93
|
+
call_api_and_parse_response(:delete, '/messages', ids: ids)
|
94
|
+
end
|
95
|
+
|
96
|
+
def delete_reserved_messages(messages)
|
97
|
+
ids = messages.map do |message|
|
98
|
+
{id: message.id, reservation_id: message.reservation_id}
|
99
|
+
end
|
100
|
+
|
101
|
+
call_api_and_parse_response(:delete, '/messages', ids: ids)
|
92
102
|
end
|
93
103
|
|
94
104
|
def add_subscribers(subscribers)
|
95
|
-
call_api_and_parse_response(:post,
|
105
|
+
call_api_and_parse_response(:post, '/subscribers',{subscribers: subscribers})
|
96
106
|
end
|
97
107
|
|
98
108
|
# `options` for backward compatibility
|
@@ -102,10 +112,12 @@ module IronMQ
|
|
102
112
|
|
103
113
|
def remove_subscribers(subscribers)
|
104
114
|
call_api_and_parse_response(:delete,
|
105
|
-
|
115
|
+
'/subscribers',
|
106
116
|
{
|
107
|
-
|
108
|
-
|
117
|
+
subscribers: subscribers,
|
118
|
+
headers: {
|
119
|
+
'Content-Type' => @client.content_type
|
120
|
+
}
|
109
121
|
})
|
110
122
|
end
|
111
123
|
|
@@ -113,31 +125,53 @@ module IronMQ
|
|
113
125
|
remove_subscribers([subscriber])
|
114
126
|
end
|
115
127
|
|
128
|
+
def replace_subscribers(subscribers)
|
129
|
+
call_api_and_parse_response(:put,
|
130
|
+
'/subscribers',
|
131
|
+
{
|
132
|
+
subscribers: subscribers,
|
133
|
+
headers: {
|
134
|
+
'Content-Type' => @client.content_type
|
135
|
+
}
|
136
|
+
})
|
137
|
+
end
|
138
|
+
|
139
|
+
def replace_subscriber(subscriber)
|
140
|
+
replace_subscribers([subscriber])
|
141
|
+
end
|
142
|
+
|
116
143
|
# `options` was kept for backward compatibility
|
117
144
|
def subscribers(options = {})
|
118
145
|
load
|
119
|
-
if
|
120
|
-
return @raw['subscribers'].map { |s| Subscriber.new(s, self, options) }
|
121
|
-
end
|
122
|
-
[]
|
123
|
-
end
|
146
|
+
return [] if info['push'].nil? || info['push']['subscribers'].nil?
|
124
147
|
|
125
|
-
|
126
|
-
add_alerts([alert])
|
148
|
+
info['push']['subscribers'].map { |s| Subscriber.new(s, self, options) }
|
127
149
|
end
|
128
150
|
|
129
151
|
def add_alerts(alerts)
|
130
|
-
call_api_and_parse_response(:
|
152
|
+
call_api_and_parse_response(:patch, '', queue: {alerts: alerts})
|
153
|
+
end
|
154
|
+
|
155
|
+
def add_alert(alert)
|
156
|
+
add_alerts([alert])
|
131
157
|
end
|
132
158
|
|
133
159
|
def remove_alerts(alerts)
|
134
|
-
call_api_and_parse_response(:delete, '/alerts', :
|
160
|
+
call_api_and_parse_response(:delete, '/alerts', alerts: alerts)
|
135
161
|
end
|
136
162
|
|
137
163
|
def remove_alert(alert)
|
138
164
|
remove_alerts([alert])
|
139
165
|
end
|
140
166
|
|
167
|
+
def replace_alerts(alerts)
|
168
|
+
call_api_and_parse_response(:put, '/alerts', alerts: alerts)
|
169
|
+
end
|
170
|
+
|
171
|
+
def clear_alerts
|
172
|
+
replace_alerts([])
|
173
|
+
end
|
174
|
+
|
141
175
|
def alerts
|
142
176
|
load
|
143
177
|
return nil unless @raw['alerts']
|
@@ -159,44 +193,42 @@ module IronMQ
|
|
159
193
|
# For now user must pass objects like `[{:body => msg1}, {:body => msg2}]`
|
160
194
|
payload.map { |msg| msg.merge(options) }
|
161
195
|
else
|
162
|
-
[options.merge(:
|
196
|
+
[options.merge(body: payload)]
|
163
197
|
end
|
164
198
|
|
165
199
|
# Do not instantiate response
|
166
|
-
res = call_api_and_parse_response(:post,
|
200
|
+
res = call_api_and_parse_response(:post, '/messages',
|
201
|
+
{messages: msgs}, false)
|
167
202
|
|
168
203
|
if instantiate
|
169
204
|
n = batch ? 2 : 1
|
170
|
-
msg_ids = res[
|
205
|
+
msg_ids = res['ids'].map { |id| {'id' => id} }
|
171
206
|
|
172
|
-
process_messages(msg_ids, {:
|
207
|
+
process_messages(msg_ids, {n: n})
|
173
208
|
else
|
174
209
|
if batch
|
175
210
|
# FIXME: Return Array of ResponseBase instead, it seems more clear than raw response
|
176
211
|
#
|
177
|
-
# res[
|
212
|
+
# res['ids'].map { |id| ResponseBase.new({'id' => id, 'msg' => res['msg']}) }
|
178
213
|
#
|
179
214
|
ResponseBase.new(res) # Backward capable
|
180
215
|
else
|
181
|
-
ResponseBase.new({
|
216
|
+
ResponseBase.new({'id' => res['ids'][0], 'msg' => res['msg']})
|
182
217
|
end
|
183
218
|
end
|
184
219
|
end
|
185
220
|
|
186
221
|
alias_method :post, :post_messages
|
187
222
|
|
188
|
-
def
|
189
|
-
|
190
|
-
|
191
|
-
return Message.new(self, {"id" => options})
|
192
|
-
end
|
193
|
-
|
194
|
-
resp = call_api_and_parse_response(:get, "/messages", options, false)
|
195
|
-
|
196
|
-
process_messages(resp["messages"], options)
|
223
|
+
def reserve_messages(options = {})
|
224
|
+
resp = call_api_and_parse_response(:post, '/reservations', options, false)
|
225
|
+
process_messages(resp['messages'], options)
|
197
226
|
end
|
198
227
|
|
199
|
-
|
228
|
+
# backwards compatibility
|
229
|
+
alias_method :get, :reserve_messages
|
230
|
+
alias_method :get_messages, :reserve_messages
|
231
|
+
alias_method :reserve, :reserve_messages
|
200
232
|
|
201
233
|
# Backward compatibility
|
202
234
|
def messages
|
@@ -205,13 +237,13 @@ module IronMQ
|
|
205
237
|
|
206
238
|
def get_message(id)
|
207
239
|
resp = call_api_and_parse_response(:get, "/messages/#{id}", {}, false)
|
208
|
-
Message.new(self, resp)
|
240
|
+
Message.new(self, resp['message'])
|
209
241
|
end
|
210
242
|
|
211
243
|
def peek_messages(options = {})
|
212
|
-
resp = call_api_and_parse_response(:get,
|
244
|
+
resp = call_api_and_parse_response(:get, '/messages', options)
|
213
245
|
|
214
|
-
process_messages(resp[
|
246
|
+
process_messages(resp['messages'], options)
|
215
247
|
end
|
216
248
|
|
217
249
|
alias_method :peek, :peek_messages
|
@@ -233,17 +265,24 @@ module IronMQ
|
|
233
265
|
|
234
266
|
alias_method :poll, :poll_messages
|
235
267
|
|
236
|
-
def call_api_and_parse_response(meth, ext_path =
|
237
|
-
|
238
|
-
response =
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
268
|
+
def call_api_and_parse_response(meth, ext_path = '', options = {},
|
269
|
+
instantiate = true, ignore404 = false)
|
270
|
+
response =
|
271
|
+
if meth.to_s == 'delete'
|
272
|
+
headers = options.delete(:headers) ||
|
273
|
+
options.delete('headers') ||
|
274
|
+
Hash.new
|
275
|
+
headers['Content-Type'] = 'application/json'
|
276
|
+
@client.parse_response(@client.send(meth,
|
277
|
+
"#{path(ext_path)}",
|
278
|
+
options, headers))
|
279
|
+
else
|
280
|
+
@client.parse_response(@client.send(meth,
|
281
|
+
"#{path(ext_path)}",
|
282
|
+
options))
|
283
|
+
end
|
284
|
+
|
285
|
+
instantiate ? ResponseBase.new(response) : response
|
247
286
|
end
|
248
287
|
|
249
288
|
private
|