mimi-messaging-sqs_sns 0.4.0 → 0.6.1

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 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