iron_mq 5.0.1 → 6.0.0.pre1
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/.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
|