mimi-messaging-sqs_sns 0.4.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b740db8e4dab81e38d1b84ecd40c508a67d4c4c8
4
- data.tar.gz: b55b8188a57c5e0b8095ba133b27dad09f17f2a2
2
+ SHA256:
3
+ metadata.gz: 1f7bfa555dbbe8a3d917d0133811c6f2af643016e5864628a8ae7ae79ec2a9fc
4
+ data.tar.gz: adc4769159cb678ca05e69c0d5b174b2d9a87064da8fcddf16916596ab14889e
5
5
  SHA512:
6
- metadata.gz: c215ab899f4217ecd11e628f9739671d569da25cd2abd8ea3ce35572c5076b09941898f18b22f9d97926a9e29a93fb1729064919643ae0119a0a4f62c860b3d1
7
- data.tar.gz: 28b7ff63ec0db04041fc173a329bf39a3179d16f50e3d72133f776806fb95c2de5572ec51f8b97681a507645a05021fd01df9b2e1d3f36feae98601f8c8f39ee
6
+ metadata.gz: 377f9dc7b50c0c3c4edd77afec14e2473fdebbfd4751a18d358c27b9c4281e3af2566f5f70c68fb228a75316d985a2f8f4cab4c74b5d233335e2986875fa88b0
7
+ data.tar.gz: becd20ef9d41f474ee072a8af75b8b885e40f47b8c34ddca61269cd413fb88368d4715808e4ca8a507b2c56e41b6db0aaf1381c0c9e1715dc4397aa4dcf1888b
data/TODO.md ADDED
@@ -0,0 +1,9 @@
1
+ # TODO
2
+
3
+ List of missing features planned for future releases.
4
+
5
+ [X] Log error and recover if the reply cannot be sent
6
+ [ ] Threadsafe TimeoutQueue
7
+ [ ] Multithreaded consumers
8
+ [ ] Subscribe to topic without a queue (Temporary queues)
9
+
@@ -4,8 +4,8 @@ require "mimi/messaging/sqs_sns"
4
4
 
5
5
  COUNT = 10
6
6
  AWS_REGION = "eu-west-1"
7
- AWS_SQS_ENDPOINT_URL = "http://localstack:4576"
8
- AWS_SNS_ENDPOINT_URL = "http://localstack:4575"
7
+ AWS_SQS_ENDPOINT_URL = "http://localstack:4566"
8
+ AWS_SNS_ENDPOINT_URL = "http://localstack:4566"
9
9
  AWS_ACCESS_KEY_ID = "foo"
10
10
  AWS_SECRET_ACCESS_KEY = "bar"
11
11
 
@@ -3,8 +3,8 @@
3
3
  require "mimi/messaging/sqs_sns"
4
4
 
5
5
  AWS_REGION = "eu-west-1"
6
- AWS_SQS_ENDPOINT_URL = "http://localstack:4576"
7
- AWS_SNS_ENDPOINT_URL = "http://localstack:4575"
6
+ AWS_SQS_ENDPOINT_URL = "http://localstack:4566"
7
+ AWS_SNS_ENDPOINT_URL = "http://localstack:4566"
8
8
  AWS_ACCESS_KEY_ID = "foo"
9
9
  AWS_SECRET_ACCESS_KEY = "bar"
10
10
 
@@ -22,7 +22,7 @@ end # class Processor
22
22
 
23
23
 
24
24
  logger = Logger.new(STDOUT)
25
- logger.level = Logger::INFO
25
+ logger.level = Logger::DEBUG
26
26
  Mimi::Messaging.use(logger: logger, serializer: Mimi::Messaging::JsonSerializer)
27
27
  Mimi::Messaging.configure(
28
28
  mq_adapter: "sqs_sns",
@@ -12,4 +12,5 @@ end # module Mimi
12
12
 
13
13
  require_relative "sqs_sns/adapter"
14
14
  require_relative "sqs_sns/consumer"
15
+ require_relative "sqs_sns/temporary_queue_consumer"
15
16
  require_relative "sqs_sns/reply_consumer"
@@ -78,6 +78,7 @@ module Mimi
78
78
  def start
79
79
  @sqs_client = Aws::SQS::Client.new(sqs_client_config)
80
80
  @sns_client = Aws::SNS::Client.new(sns_client_config)
81
+ check_availability!
81
82
  end
82
83
 
83
84
  def stop
@@ -189,7 +190,7 @@ module Mimi
189
190
  response,
190
191
  __request_id: message.headers[:__request_id]
191
192
  )
192
- deliver_message_queue(reply_to, response_message)
193
+ deliver_query_respone(reply_to, response_message)
193
194
  else
194
195
  processor.call_command(method_name, message, {})
195
196
  end
@@ -218,6 +219,45 @@ module Mimi
218
219
  end
219
220
  end
220
221
 
222
+ # Creates a new queue
223
+ #
224
+ # @param queue_name [String] name of the topic to be created
225
+ # @return [String] a new queue URL
226
+ #
227
+ def create_queue(queue_name)
228
+ fqn = sqs_sns_converted_full_name(queue_name)
229
+ Mimi::Messaging.log "Creating a queue: #{fqn}"
230
+ result = sqs_client.create_queue(queue_name: fqn)
231
+ result.queue_url
232
+ rescue StandardError => e
233
+ raise Mimi::Messaging::ConnectionError, "Failed to create queue '#{queue_name}': #{e}"
234
+ end
235
+
236
+
237
+ # Finds a queue URL for a queue with given name.
238
+ #
239
+ # If an existing queue with this name is not found,
240
+ # the method will try to create a new one.
241
+ #
242
+ # @param queue_name [String]
243
+ # @return [String] a queue URL
244
+ #
245
+ def find_or_create_queue(queue_name)
246
+ queue_registry(queue_name) || create_queue(queue_name)
247
+ end
248
+
249
+ # Deletes a queue identified by the queue URL
250
+ #
251
+ # @param queue_url [String]
252
+ #
253
+ def delete_queue(queue_url)
254
+ Mimi::Messaging.log "Deleting a queue: #{queue_url}"
255
+ sqs_client.delete_queue(queue_url: queue_url)
256
+ rescue StandardError => e
257
+ raise Mimi::Messaging::ConnectionError,
258
+ "Failed to delete queue with url '#{queue_url}': #{e}"
259
+ end
260
+
221
261
  private
222
262
 
223
263
  # Returns configuration parameters for AWS SQS client
@@ -248,18 +288,21 @@ module Mimi
248
288
  params.compact
249
289
  end
250
290
 
251
- # Creates a new queue
291
+ # Checks SQS and SNS clients availability
252
292
  #
253
- # @param queue_name [String] name of the topic to be created
254
- # @return [String] a new queue URL
293
+ # @raise [Mimi::Messaging::ConnectionError]
255
294
  #
256
- def create_queue(queue_name)
257
- fqn = sqs_sns_converted_full_name(queue_name)
258
- Mimi::Messaging.log "Creating a queue: #{fqn}"
259
- result = sqs_client.create_queue(queue_name: fqn)
260
- result.queue_url
261
- rescue StandardError => e
262
- raise Mimi::Messaging::ConnectionError, "Failed to create queue '#{queue_name}': #{e}"
295
+ def check_availability!
296
+ begin
297
+ queue_registry("test")
298
+ rescue StandardError => e
299
+ raise Mimi::Messaging::ConnectionError, "SQS connection is not available: #{e}"
300
+ end
301
+ begin
302
+ topic_registry("test")
303
+ rescue StandardError => e
304
+ raise Mimi::Messaging::ConnectionError, "SNS connection is not available: #{e}"
305
+ end
263
306
  end
264
307
 
265
308
  # Delivers a message to a queue with given URL.
@@ -272,7 +315,7 @@ module Mimi
272
315
  unless message.is_a?(Mimi::Messaging::Message)
273
316
  raise ArgumentError, "Message is expected as argument"
274
317
  end
275
- Mimi::Messaging.log "Delivering message to: #{queue_url}"
318
+ Mimi::Messaging.log "Delivering message to: #{queue_url}, headers: #{message.headers}"
276
319
  sqs_client.send_message(
277
320
  queue_url: queue_url,
278
321
  message_body: serialize(message),
@@ -284,6 +327,23 @@ module Mimi
284
327
  raise Mimi::Messaging::ConnectionError, "Failed to deliver message to '#{queue_url}': #{e}"
285
328
  end
286
329
 
330
+ # Delivers a message as a response to a QUERY
331
+ #
332
+ # Responses are allowed to fail. There can be a number of reasons
333
+ # why responses fail: reply queue does not exist (anymore?),
334
+ # response message is too big. In any case the error is reported,
335
+ # but the QUERY message is acknowledged as a successfully processed.
336
+ #
337
+ # @param queue_url [String]
338
+ # @param message [Mimi::Messaging::Message]
339
+ #
340
+ def deliver_query_respone(queue_url, message)
341
+ deliver_message_queue(queue_url, message)
342
+ rescue Mimi::Messaging::ConnectionError => e
343
+ Mimi::Messaging.logger&.warn("Failed to deliver QRY response: #{e}")
344
+ # NOTE: error is recovered
345
+ end
346
+
287
347
  # Returns URL of a queue with a given name.
288
348
  #
289
349
  # If the queue with given name does not exist, returns nil
@@ -300,6 +360,8 @@ module Mimi
300
360
  end
301
361
  rescue Aws::SQS::Errors::NonExistentQueue
302
362
  nil
363
+ rescue StandardError => e
364
+ raise Mimi::Messaging::ConnectionError, "Failed to get queue url '#{queue_name}': #{e}"
303
365
  end
304
366
 
305
367
  # Converts a topic or queue name to a fully qualified (with namespace)
@@ -329,18 +391,6 @@ module Mimi
329
391
  )
330
392
  end
331
393
 
332
- # Finds a queue URL for a queue with given name.
333
- #
334
- # If an existing queue with this name is not found,
335
- # the method will try to create a new one.
336
- #
337
- # @param queue_name [String]
338
- # @return [String] a queue URL
339
- #
340
- def find_or_create_queue(queue_name)
341
- queue_registry(queue_name) || create_queue(queue_name)
342
- end
343
-
344
394
  # Returns the configured reply listener for this process
345
395
  #
346
396
  # @return [ReplyConsumer]
@@ -348,8 +398,7 @@ module Mimi
348
398
  def reply_consumer
349
399
  @reply_consumer ||= begin
350
400
  reply_queue_name = options[:mq_reply_queue_prefix] + SecureRandom.hex(8)
351
- reply_queue_url = create_queue(reply_queue_name)
352
- Mimi::Messaging::SQS_SNS::ReplyConsumer.new(self, reply_queue_url)
401
+ Mimi::Messaging::SQS_SNS::ReplyConsumer.new(self, reply_queue_name)
353
402
  end
354
403
  end
355
404
 
@@ -4,20 +4,15 @@ module Mimi
4
4
  module Messaging
5
5
  module SQS_SNS
6
6
  #
7
- # Message processor for SQS queues
7
+ # Message consumer for SQS queues
8
8
  #
9
9
  class Consumer
10
10
  def initialize(adapter, queue_url, &block)
11
- @block = block
12
11
  @stop_requested = false
13
12
  Mimi::Messaging.log "Starting consumer for: #{queue_url}"
14
13
  @consumer_thread = Thread.new do
15
14
  while not @stop_requested do
16
- message = read_message(adapter, queue_url)
17
- next unless message
18
- Mimi::Messaging.log "Read message from: #{queue_url}"
19
- block.call(message)
20
- ack_message(adapter, queue_url, message)
15
+ read_and_process_message(adapter, queue_url, block)
21
16
  end
22
17
  Mimi::Messaging.log "Stopping consumer for: #{queue_url}"
23
18
  end
@@ -30,6 +25,26 @@ module Mimi
30
25
 
31
26
  private
32
27
 
28
+ # A method invoked in a loop to read/wait for a message
29
+ # from the associated queue and process it
30
+ #
31
+ # @param adapter [Mimi::Messaging::SQS_SNS::Adapter]
32
+ # @param queue_url [String]
33
+ # @param block [Proc] a block to be invoked when a message is received
34
+ #
35
+ def read_and_process_message(adapter, queue_url, block)
36
+ message = read_message(adapter, queue_url)
37
+ return unless message
38
+ Mimi::Messaging.log "Read message from: #{queue_url}"
39
+ block.call(message)
40
+ ack_message(adapter, queue_url, message)
41
+ rescue StandardError => e
42
+ Mimi::Messaging.logger&.error(
43
+ "#{self.class}: failed to read and process message from: #{queue_url}," \
44
+ " error: (#{e.class}) #{e}"
45
+ )
46
+ end
47
+
33
48
  def read_message(adapter, queue_url)
34
49
  result = adapter.sqs_client.receive_message(
35
50
  queue_url: queue_url,
@@ -8,25 +8,23 @@ module Mimi
8
8
  # and passes them to registered Queues (see Ruby ::Queue class).
9
9
  #
10
10
  class ReplyConsumer
11
- attr_reader :reply_queue_url
11
+ attr_reader :reply_queue_name, :reply_queue_url
12
12
 
13
- def initialize(adapter, reply_queue_url)
13
+ def initialize(adapter, reply_queue_name)
14
14
  @mutex = Mutex.new
15
15
  @queues = {}
16
16
  @adapter = adapter
17
- @reply_queue_url = reply_queue_url
18
- @consumer = Consumer.new(adapter, reply_queue_url) do |message|
17
+ @reply_queue_name = reply_queue_name
18
+ @consumer = TemporaryQueueConsumer.new(adapter, reply_queue_name) do |message|
19
19
  dispatch_message(message)
20
20
  end
21
+ @reply_queue_url = @consumer.queue_url
21
22
  end
22
23
 
23
24
  def stop
24
- begin
25
- @consumer.stop
26
- rescue StandardError => e
27
- raise Mimi::Messaging::Error, "Failed to stop consumer: #{e}"
28
- end
29
- # TODO: adapter.sqs_client.delete_queue(reply_queue_url)
25
+ @consumer.stop
26
+ rescue StandardError => e
27
+ raise Mimi::Messaging::Error, "Failed to stop reply consumer: #{e}"
30
28
  end
31
29
 
32
30
  # Register a new request_id to listen for.
@@ -65,6 +63,7 @@ module Mimi
65
63
  @mutex.synchronize do
66
64
  headers = deserialize_headers(message)
67
65
  request_id = headers[:__request_id]
66
+ Mimi::Messaging.log "dispatching response, headers:#{headers}"
68
67
  queue = @queues.delete(request_id)
69
68
  end
70
69
  queue&.push(message)
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mimi
4
+ module Messaging
5
+ module SQS_SNS
6
+ #
7
+ # Temporary queue consumer creates a temporary queue
8
+ # and attaches to it. The queue will be deleted
9
+ # on consumer shutdown.
10
+ #
11
+ class TemporaryQueueConsumer
12
+ attr_reader :queue_url
13
+
14
+ def initialize(adapter, queue_name, &block)
15
+ @adapter = adapter
16
+ @queue_url = adapter.find_or_create_queue(queue_name)
17
+ @consumer = Consumer.new(adapter, @queue_url, &block)
18
+ end
19
+
20
+ def stop
21
+ @consumer.stop
22
+ @adapter.delete_queue(queue_url)
23
+ rescue StandardError => e
24
+ raise Mimi::Messaging::Error, "Failed to stop temporary queue consumer: #{e}"
25
+ end
26
+ end # class TemporaryQueueConsumer
27
+ end # module SQS_SNS
28
+ end # module Messaging
29
+ end # module Mimi
@@ -3,7 +3,7 @@
3
3
  module Mimi
4
4
  module Messaging
5
5
  module SQS_SNS
6
- VERSION = "0.4.0"
6
+ VERSION = "0.6.1"
7
7
  end
8
8
  end
9
9
  end
@@ -39,6 +39,6 @@ Gem::Specification.new do |spec|
39
39
 
40
40
  spec.add_development_dependency "bundler", "~> 2.0"
41
41
  spec.add_development_dependency "pry", "~> 0.12"
42
- spec.add_development_dependency "rake", "~> 10.0"
42
+ spec.add_development_dependency "rake", "~> 12.0", ">= 12.3.3"
43
43
  spec.add_development_dependency "rspec", "~> 3.0"
44
44
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mimi-messaging-sqs_sns
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Kukushkin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-10-13 00:00:00.000000000 Z
11
+ date: 2020-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mimi-messaging
@@ -86,14 +86,20 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '10.0'
89
+ version: '12.0'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 12.3.3
90
93
  type: :development
91
94
  prerelease: false
92
95
  version_requirements: !ruby/object:Gem::Requirement
93
96
  requirements:
94
97
  - - "~>"
95
98
  - !ruby/object:Gem::Version
96
- version: '10.0'
99
+ version: '12.0'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 12.3.3
97
103
  - !ruby/object:Gem::Dependency
98
104
  name: rspec
99
105
  requirement: !ruby/object:Gem::Requirement
@@ -123,6 +129,7 @@ files:
123
129
  - LICENSE.txt
124
130
  - README.md
125
131
  - Rakefile
132
+ - TODO.md
126
133
  - bin/console
127
134
  - bin/setup
128
135
  - examples/event.rb
@@ -133,6 +140,7 @@ files:
133
140
  - lib/mimi/messaging/sqs_sns/adapter.rb
134
141
  - lib/mimi/messaging/sqs_sns/consumer.rb
135
142
  - lib/mimi/messaging/sqs_sns/reply_consumer.rb
143
+ - lib/mimi/messaging/sqs_sns/temporary_queue_consumer.rb
136
144
  - lib/mimi/messaging/sqs_sns/version.rb
137
145
  - mimi-messaging-sqs_sns.gemspec
138
146
  homepage: https://github.com/kukushkin/mimi-messaging-sqs_sns
@@ -157,8 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
157
165
  - !ruby/object:Gem::Version
158
166
  version: '0'
159
167
  requirements: []
160
- rubyforge_project:
161
- rubygems_version: 2.6.14.4
168
+ rubygems_version: 3.0.3
162
169
  signing_key:
163
170
  specification_version: 4
164
171
  summary: AWS SQS/SNS adapter for mimi-messaging