eventq 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +336 -0
  3. data/bin/console +14 -0
  4. data/bin/setup +8 -0
  5. data/lib/eventq/aws.rb +38 -0
  6. data/lib/eventq/eventq_aws/README.md +53 -0
  7. data/lib/eventq/eventq_aws/aws_eventq_client.rb +120 -0
  8. data/lib/eventq/eventq_aws/aws_queue_client.rb +64 -0
  9. data/lib/eventq/eventq_aws/aws_queue_manager.rb +68 -0
  10. data/lib/eventq/eventq_aws/aws_queue_worker.rb +168 -0
  11. data/lib/eventq/eventq_aws/aws_status_checker.rb +25 -0
  12. data/lib/eventq/eventq_aws/aws_subscription_manager.rb +65 -0
  13. data/lib/eventq/eventq_aws/jruby/aws_queue_worker.rb +370 -0
  14. data/lib/eventq/eventq_aws/sns.rb +64 -0
  15. data/lib/eventq/eventq_aws/sqs.rb +112 -0
  16. data/lib/eventq/eventq_base/configuration.rb +33 -0
  17. data/lib/eventq/eventq_base/event_raised_exchange.rb +7 -0
  18. data/lib/eventq/eventq_base/event_raised_queue.rb +7 -0
  19. data/lib/eventq/eventq_base/eventq_client_contract.rb +9 -0
  20. data/lib/eventq/eventq_base/eventq_logger.rb +28 -0
  21. data/lib/eventq/eventq_base/exceptions/invalid_signature_exception.rb +9 -0
  22. data/lib/eventq/eventq_base/exceptions/worker_thread_error.rb +10 -0
  23. data/lib/eventq/eventq_base/exceptions.rb +2 -0
  24. data/lib/eventq/eventq_base/exchange.rb +5 -0
  25. data/lib/eventq/eventq_base/message_args.rb +23 -0
  26. data/lib/eventq/eventq_base/nonce_manager.rb +57 -0
  27. data/lib/eventq/eventq_base/queue.rb +27 -0
  28. data/lib/eventq/eventq_base/queue_message.rb +31 -0
  29. data/lib/eventq/eventq_base/queue_worker_contract.rb +23 -0
  30. data/lib/eventq/eventq_base/serialization_providers/binary_serialization_provider.rb +15 -0
  31. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/array_writer.rb +20 -0
  32. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/attribute_writer.rb +24 -0
  33. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/class_writer.rb +20 -0
  34. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/date_time_writer.rb +33 -0
  35. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/date_writer.rb +22 -0
  36. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/hash_writer.rb +18 -0
  37. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/rational_writer.rb +20 -0
  38. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/serializer.rb +17 -0
  39. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/time_writer.rb +18 -0
  40. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/value_writer.rb +16 -0
  41. data/lib/eventq/eventq_base/serialization_providers/jruby/oj.rb +10 -0
  42. data/lib/eventq/eventq_base/serialization_providers/jruby/oj_serialization_provider.rb +25 -0
  43. data/lib/eventq/eventq_base/serialization_providers/jruby.rb +2 -0
  44. data/lib/eventq/eventq_base/serialization_providers/json_serialization_provider.rb +28 -0
  45. data/lib/eventq/eventq_base/serialization_providers/oj_serialization_provider.rb +24 -0
  46. data/lib/eventq/eventq_base/serialization_providers.rb +36 -0
  47. data/lib/eventq/eventq_base/signature_providers/sha256_signature_provider.rb +31 -0
  48. data/lib/eventq/eventq_base/signature_providers.rb +44 -0
  49. data/lib/eventq/eventq_base/subscription_manager_contract.rb +13 -0
  50. data/lib/eventq/eventq_base/version.rb +3 -0
  51. data/lib/eventq/eventq_base/worker_id.rb +20 -0
  52. data/lib/eventq/eventq_rabbitmq/README.md +36 -0
  53. data/lib/eventq/eventq_rabbitmq/default_queue.rb +12 -0
  54. data/lib/eventq/eventq_rabbitmq/jruby/rabbitmq_queue_worker.rb +367 -0
  55. data/lib/eventq/eventq_rabbitmq/rabbitmq_eventq_client.rb +140 -0
  56. data/lib/eventq/eventq_rabbitmq/rabbitmq_queue_client.rb +54 -0
  57. data/lib/eventq/eventq_rabbitmq/rabbitmq_queue_manager.rb +104 -0
  58. data/lib/eventq/eventq_rabbitmq/rabbitmq_queue_worker.rb +168 -0
  59. data/lib/eventq/eventq_rabbitmq/rabbitmq_status_checker.rb +62 -0
  60. data/lib/eventq/eventq_rabbitmq/rabbitmq_subscription_manager.rb +54 -0
  61. data/lib/eventq/queue_worker.rb +241 -0
  62. data/lib/eventq/rabbitmq.rb +49 -0
  63. data/lib/eventq/worker_status.rb +64 -0
  64. data/lib/eventq.rb +25 -0
  65. metadata +289 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 29d2e0dbde90c017daf4729cf39dd998c499b09f5a54d329d0546048f812b729
4
+ data.tar.gz: 08ab2c25998abdaf811169d26b1140107c671d1040091cc2294d0b5c6df87baf
5
+ SHA512:
6
+ metadata.gz: 82af850fe3d231f5966150a655286e057fcb71bea23900e6924381d186dcadf594011c9054eb7a9c87e35fb0cb768dca8dc166de81bd54801f94016d431e9bdd
7
+ data.tar.gz: 13d4ee3700ee280297cd731c25c9448c00171384c53b21bc35d69cc6c23c9c3b275a0c79d327620d58ce7051134a42237125c0a02f0bd4238fa73d5d4c9f02b0
data/README.md ADDED
@@ -0,0 +1,336 @@
1
+ # EventQ
2
+
3
+ [![Build Status](https://travis-ci.org/Sage/eventq.svg?branch=master)](https://travis-ci.org/Sage/eventq)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/87205b497059e2733bdc/maintainability)](https://codeclimate.com/github/Sage/eventq/maintainability)
5
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/87205b497059e2733bdc/test_coverage)](https://codeclimate.com/github/Sage/eventq/test_coverage)
6
+
7
+ Welcome to EventQ.
8
+
9
+ EventQ is an event service bus framework for decoupling services and application processes.
10
+
11
+ Events are raised through the EventQ client and subscribers of the event types will be broadcast the event via a persistent queue for guaranteed delivery.
12
+
13
+ EventQ has a base layer which allows different queue implementations to be created abstracting the specific queue implementation details away from your application code.
14
+ EventQ comes with two default adapter that support RabbitMq and AWS SNS/SQS
15
+
16
+ [AWS README](./lib/eventq/eventq_aws/README.md)
17
+
18
+ [RabbitMq README](./lib/eventq/eventq_rabbitmq/README.md)
19
+
20
+ ## Installation
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ ```ruby
25
+ gem 'eventq'
26
+ ```
27
+
28
+ And then execute:
29
+
30
+ $ bundle install
31
+
32
+ Or install it yourself as:
33
+
34
+ $ gem install eventq
35
+
36
+ ## Usage
37
+
38
+ ### Queue adapters
39
+ There are two adapters built into EventQ. One supports AWS SNS/SQS and the other supports RabbitMq
40
+ In order to use the appropriate adapter you simply need to require the necessary file.
41
+
42
+ AWS
43
+ ```ruby
44
+ require 'eventq/aws'
45
+ ```
46
+
47
+ RabbitMq
48
+ ```ruby
49
+ require 'eventq/rabbitmq'
50
+ ```
51
+
52
+ ### Queue
53
+
54
+ A subscription queue should be defined to receive any events raised for the subscribed event type.
55
+
56
+ **Attributes**
57
+
58
+ - **allow_retry** [Bool] [Optional] [Default=false] This determines if the queue should allow processing failures to be retried.
59
+ - **allow_retry_backoff** [Bool] [Optional] [Default=false] This is used to specify if failed messages that retry should incrementally backoff.
60
+ - **dlq** [EventQ::Queue] [Optional] [Default=nil] A queue that will receive the messages which were not successfully processed after maximum number of receives by consumers. This is created at the same time as the parent queue.
61
+ - **max_retry_attempts** [Int] [Optional] [Default=5] This is used to specify the max number of times an event should be allowed to retry before failing.
62
+ - **max_receive_count** [Int] [Optional] [Default=30] The maximum number of times that a message can be received by consumers. When this value is exceeded for a message the message will be automatically sent to the Dead Letter Queue.
63
+ - **max_retry_delay** [Int] [Optional] This is used to specify the max retry delay that should apply when allowing incremental back off.
64
+ - **name** [String] [Required] This is the name of the queue, it must be unique.
65
+ - **require_signature** [Bool] [Optional] [Default=false] This is used to specify if messages within this queue must be signed.
66
+ - **retry_delay** [Int] [Optional] [Default=30000] This is used to specify the time delay in milliseconds before a failed message is re-added to the subscription queue.
67
+
68
+ **Example**
69
+
70
+ ```ruby
71
+ # Create a queue that allows retries and accepts a maximum of 3 retries with a 20 second delay between retries.
72
+ class DataChangeAddressQueue < Queue
73
+ def initialize
74
+ @name = 'Data.Change.Address'
75
+ @allow_retry = true
76
+ @retry_delay = 20000
77
+ @max_retry_attempts = 3
78
+ end
79
+ end
80
+ ```
81
+
82
+ ### SubscriptionManager
83
+
84
+ In order to receive events within a subscription queue it must subscribe to the type of the event it should receive.
85
+
86
+ #### #subscribe
87
+
88
+ This method is called to subscribe a queue to an event type.
89
+
90
+ **Params:**
91
+
92
+ - **event_type** [String] [Required] This is the unique name of the event type to subscribe to.
93
+ - **queue** [Queue] [Required] This is the queue definition object that represents the queue to subscribe.
94
+
95
+ **Example**
96
+
97
+ #create an instant of the queue definition
98
+ queue = DateChangeAddressQueue.new
99
+
100
+ #subscribe the queue definition to an event type
101
+ subscription_manager.subscribe('Data:Change:Address', queue)
102
+
103
+ #### #unsubscribe
104
+
105
+ This method is called to unsubscribe a queue.
106
+
107
+ **Params:**
108
+
109
+ - **queue** [Queue] [Required] This is the queue definition object that represents the queue to unsubscribe.
110
+
111
+ **Example**
112
+
113
+ #create an instant of the queue definition
114
+ queue = DateChangeAddressQueue.new
115
+
116
+ #subscribe the queue definition to an event type
117
+ subscription_manager.unsubscribe(queue)
118
+
119
+
120
+ ### QueueWorker
121
+
122
+ The queue worker is used to process subscribed events from a subscription queue. The QueueWorker uses threads and is capable of processing subscribed events in parallel.
123
+
124
+ #### #on_retry_exceeded
125
+
126
+ The on_retry_exceeded method allows you to specify a block that should execute whenever an event fails to process and exceeds the maximum allowed retry attempts specified by the queue. The event object passed to the block is a **[QueueMessage]** object.
127
+
128
+ **Example**
129
+
130
+ worker.on_retry_exceeded do |event|
131
+ ....
132
+ #Do something with the failed event
133
+ ....
134
+ end
135
+
136
+ #### #on_retry
137
+
138
+ The on_retry method allows you to specify a block that should execute whenever an event fails to process and is retried. The event object passed to the block is a **[QueueMessage]** object, and the abort arg is a Boolean that specifies if the message was aborted (true or false).
139
+
140
+
141
+ [NOTE: The message will be automatically retried so no manual action is required, this is to allow additional logging etc to be performed]
142
+
143
+ **Example**
144
+
145
+ worker.on_retry do |event, abort|
146
+ ....
147
+ #Do something with the failed event
148
+ ....
149
+ end
150
+
151
+ #### #on_error
152
+
153
+ The on_error method allows you to specify a block that should execute whenever an unhandled error occurs with the worker. The could be communication failures with the queue etc.
154
+
155
+ **Example**
156
+
157
+ worker.on_error do |error|
158
+ ....
159
+ #Do something with the error
160
+ ....
161
+ end
162
+
163
+ #### #start
164
+
165
+ The start method is used to specify a block to process received events and start the worker.
166
+
167
+ **Params:**
168
+
169
+ - **queue** [Queue] [Required] This is the queue definition for the subscription queue this worker should process.
170
+ - **options** [Hash] [Optional] This is an options hash to configure the queue worker.
171
+
172
+ > **Options:**
173
+ >
174
+ > - **:fork_count** [Int] [Optional] [Default=1] This is the number of process forks that the queue worker will use to process events in parallel (Additional forks should be added to take advantage of multi core CPU's).
175
+ >
176
+ > - **:thread_count** [Int] [Optional] [Default=5] This is the number of threads that the queue worker should use to process events in parallel.
177
+ >
178
+ > - **:sleep** [Number] [Optional] [Default=15] This is the number of seconds a thread should sleep before attempting to request another event from the subscription queue when no event has been received.
179
+ >
180
+ > - **:wait** [Bool] [Optional] This is used to specify that the start method should block the calling thread and wait until all parallel threads have finished. (This can be used to ensure that the background process running the worker does not exit).
181
+ >
182
+ > **Block arguments:**
183
+ > - **content** [Object] This is the content of the received event.
184
+ >
185
+ > - **type** [String] This is the type of the received event.
186
+ >
187
+ > - **retry_attempts** [Int] This is the number of times the received event has been retried.
188
+
189
+ **Example**
190
+
191
+ #start the queue worker
192
+ worker.start(queue, {:thread_count => 8, :sleep => 30 }) do |content,type,retry_attempts|
193
+ ....
194
+ #add event processing code here
195
+ ....
196
+ end
197
+
198
+ #### #stop
199
+
200
+ This method is called to stop the QueueWorker and all threads.
201
+
202
+ > **Note:** This is only available when the :wait option has not been specified for the **#start** method.
203
+
204
+ **Example**
205
+
206
+ #stop the worker
207
+ worker.stop
208
+
209
+ ### QueueMessage
210
+
211
+ The **[QueueMessage]** is used internally to represent an event within the various queues. It is also returned as a parameter to the #on_retry_exceeded block of a [QueueWorker].
212
+
213
+ **Attributes:**
214
+
215
+ - **type** [String] This is the type of the event contained.
216
+ - **content** [Object] This is the event content.
217
+ - **retry_attempts** [Int] This is the number of times this event message has been retried.
218
+ - **created** [DateTime] this is when the event was initial raised.
219
+
220
+ ### Configuration
221
+
222
+ The `EventQ::Configuration` class allows global configuration options to be specified.
223
+
224
+ #### serialization_provider
225
+
226
+ This is used to specify the serialization provider that should be used for event serialization & deserialization.
227
+
228
+ > **Options:**
229
+ >
230
+ > - **OJ_PROVIDER** [Default] This is a serialization provider that uses the 'oj' gem to handle serialization & deserialization.
231
+ > - **JSON_PROVIDER** This is a serialization provider that uses the 'json' gem to handle serialization & deserialization.
232
+
233
+ #set the serialization provider configuration to the OJ_PROVIDER
234
+ EventQ::Configuration.serialization_provider = EventQ::SerializationProviders::OJ_PROVIDER
235
+ ..
236
+
237
+ #set the serialization provider configuration to the JSON_PROVIDER
238
+ EventQ::Configuration.serialization_provider = EventQ::SerializationProviders::JSON_PROVIDER
239
+
240
+ #### signature_provider
241
+
242
+ This is used to specify the signature provider that should be used for message signing.
243
+
244
+ > **Options:**
245
+ >
246
+ > - **SHA256** [Default] This is provider uses SHA256 to create message signatures.
247
+
248
+ #### signature_secret
249
+
250
+ This is used to specify the signature secret that should be used for message signing.
251
+
252
+ #set the signature secret
253
+ EventQ::Configuration.signature_secret = 'secret key'
254
+
255
+
256
+ ### NonceManager
257
+
258
+ The NonceManager is used to prevent duplicate messages from being processed. Each event message that is raised is given a unique identifier, most message queue providers guarantee at least once delivery which may result in the message being delivered more than once. If your use case needs to enforce once only processing then
259
+ the NonceManager can be configured to prevent duplicate messages from being processed. (It is a distributed store that currently uses redis locks to ensure accuracy between scaled out workers)
260
+
261
+ #### configure
262
+
263
+ This method is called to configure the NonceManager, and must be called before starting the queue worker to be active.
264
+
265
+ **Params:**
266
+
267
+ - **server** [String] [Required] This is redis server url.
268
+ - **timeout** [Integer] [Optional] [Default=10000 (10 seconds)] This is the time in milliseconds that should be used for the initial nonce lock (this value should be low so as to not affect failure retries but long enough to cover the processing of the received message).
269
+ - **lifespan** [Integer] [Optional] [Default=3600000 (60 minutes)] This is the length of time the nonce should be kept for after processing of a message has completed.
270
+
271
+ **Example**
272
+
273
+ EventQ::NonceManager.configure(server: 'redis://127.0.0.1:6379')
274
+
275
+
276
+ ### Namespace
277
+
278
+ This attribute is used to specify a namespace for all events and queues to be created within.
279
+
280
+ **Example**
281
+
282
+ EventQ.namespace = 'development'
283
+
284
+ ### StatusChecker
285
+
286
+ The status checker is used to verify the status of a queue or event type (topic/exchange).
287
+
288
+ ####queue?
289
+
290
+ This method is called to verify connection to a queue.
291
+
292
+ **Params:**
293
+
294
+ - **queue** [EventQ::Queue] [Required] This is a queue definition object.
295
+
296
+ **Return** [Boolean] (True or False)
297
+
298
+
299
+ **Example**
300
+
301
+ available = status_checker.queue?(queue)
302
+
303
+ ####event_type?
304
+
305
+ This method is called to verify connection to an event_type (topic/exchange).
306
+
307
+ **Params:**
308
+
309
+ - **event_type** [String] [Required] This is the unique identifier of the event_type.
310
+
311
+ **Return** [Boolean] (True or False)
312
+
313
+
314
+ **Example**
315
+
316
+ available = status_checker.event_type?(event_type)
317
+
318
+
319
+
320
+ ## Development
321
+
322
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
323
+
324
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
325
+
326
+ ## Contributing
327
+
328
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sage/eventq. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
329
+
330
+
331
+ ## License
332
+
333
+ EventQ is available as open source under the terms of the
334
+ [MIT licence](https://github.com/Sage/eventq/blob/master/LICENSE).
335
+
336
+ Copyright (c) 2018 Sage Group Plc. All rights reserved.
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "eventq"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/eventq/aws.rb ADDED
@@ -0,0 +1,38 @@
1
+ require 'aws-sdk-core'
2
+ require 'eventq'
3
+
4
+ require_relative './eventq_aws/aws_eventq_client'
5
+ require_relative './eventq_aws/sns'
6
+ require_relative './eventq_aws/sqs'
7
+ require_relative './eventq_aws/aws_queue_client'
8
+ require_relative './eventq_aws/aws_queue_manager'
9
+ require_relative './eventq_aws/aws_subscription_manager'
10
+ require_relative './eventq_aws/aws_status_checker'
11
+
12
+ if RUBY_PLATFORM =~ /java/
13
+ require_relative './eventq_aws/jruby/aws_queue_worker'
14
+ else
15
+ require_relative './eventq_aws/aws_queue_worker'
16
+ end
17
+
18
+ module EventQ
19
+ def self.namespace
20
+ @namespace
21
+ end
22
+ def self.namespace=(value)
23
+ @namespace = value
24
+ end
25
+ def self.create_event_type(event_type)
26
+ if EventQ.namespace == nil
27
+ return event_type
28
+ end
29
+ return "#{EventQ.namespace}-#{event_type}"
30
+ end
31
+ def self.create_queue_name(queue_name)
32
+ if EventQ.namespace == nil
33
+ return queue_name
34
+ end
35
+ return "#{EventQ.namespace}-#{queue_name}"
36
+ end
37
+ end
38
+
@@ -0,0 +1,53 @@
1
+ # EventQ [AWS]
2
+
3
+ Welcome to EventQ. This gem contains the AWS implementations of the EventQ framework components.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application:
8
+
9
+ ```ruby
10
+ require 'eventq/aws'
11
+ ```
12
+
13
+ ## Development
14
+
15
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
16
+
17
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
18
+
19
+ ### Preparing the Docker images
20
+
21
+ Run the setup script of eventq_aws to build the environment. This will create the `eventq/aws` image.
22
+
23
+ $ cd script
24
+ $ ./setup.sh
25
+
26
+ ### Running the tests
27
+
28
+ By default, the full test suite will run against the mock AWS services defined in the docker-compose.yml file.
29
+
30
+ If you want to run the tests with AWS directly, you will need an AWS account. Put your credentials into the `.aws.env` file in the parent directory.
31
+
32
+ $ cp ../.aws.env.template ../.aws.env
33
+ $ vi ../.aws.env
34
+
35
+ Run the whole test suite:
36
+
37
+ $ cd script
38
+ $ ./test.sh
39
+
40
+ You can run the specs that don't depend on an AWS account with:
41
+
42
+ $ cd script
43
+ $ ./test.sh --tag ~integration
44
+
45
+ ## Contributing
46
+
47
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sage/eventq. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
48
+
49
+
50
+ ## License
51
+
52
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
53
+
@@ -0,0 +1,120 @@
1
+ module EventQ
2
+ module Amazon
3
+ # Implements a general interface to raise an event
4
+ # EventQ::RabbitMq::EventQClient is the sister-class which does the same for RabbitMq
5
+ class EventQClient
6
+
7
+ def initialize(options)
8
+
9
+ if options[:client] == nil
10
+ raise ':client (QueueClient) must be specified.'.freeze
11
+ end
12
+
13
+ @client = options[:client]
14
+
15
+ @serialization_manager = EventQ::SerializationProviders::Manager.new
16
+ @signature_manager = EventQ::SignatureProviders::Manager.new
17
+
18
+ #this array is used to record known event types
19
+ @known_event_types = []
20
+
21
+ end
22
+
23
+ def registered?(event_type)
24
+ @known_event_types.include?(event_type)
25
+ end
26
+
27
+ def register_event(event_type)
28
+ if registered?(event_type)
29
+ return true
30
+ end
31
+
32
+ @client.sns_helper.create_topic_arn(event_type)
33
+ @known_event_types << event_type
34
+ true
35
+ end
36
+
37
+ def publish(topic:, event:, context: {})
38
+ raise_event(topic, event, context)
39
+ end
40
+
41
+ def raise_event(event_type, event, context = {})
42
+ register_event(event_type)
43
+
44
+ with_prepared_message(event_type, event, context) do |message|
45
+ topic_arn = topic_arn(event_type)
46
+ response = @client.sns.publish(
47
+ topic_arn: topic_arn,
48
+ message: message,
49
+ subject: event_type
50
+ )
51
+
52
+ EventQ.logger.debug do
53
+ "[#{self.class} #raise_event] - Published to SNS with topic_arn: #{topic_arn} | event_type: #{event_type} | Message: #{message}"
54
+ end
55
+
56
+ response
57
+ end
58
+ end
59
+
60
+ def raise_event_in_queue(event_type, event, queue, delay, context = {})
61
+ queue_url = @client.sqs_helper.get_queue_url(queue)
62
+ with_prepared_message(event_type, event, context) do |message|
63
+
64
+ response = @client.sqs.send_message(
65
+ queue_url: queue_url,
66
+ message_body: sqs_message_body_for(message),
67
+ delay_seconds: delay
68
+ )
69
+
70
+ EventQ.logger.debug do
71
+ "[#{self.class} #raise_event_in_queue] - Raised event to SQS queue: #{queue_url} | event_type: #{event_type} | Message: #{message}"
72
+ end
73
+
74
+ response
75
+ end
76
+ end
77
+
78
+ def new_message
79
+ EventQ::QueueMessage.new
80
+ end
81
+
82
+ private
83
+
84
+ def with_prepared_message(event_type, event, context)
85
+ qm = new_message
86
+ qm.content = event
87
+ qm.type = event_type
88
+ qm.context = context
89
+ qm.content_type = event.class.to_s
90
+
91
+ if EventQ::Configuration.signature_secret != nil
92
+ provider = @signature_manager.get_provider(EventQ::Configuration.signature_provider)
93
+ qm.signature = provider.write(message: qm, secret: EventQ::Configuration.signature_secret)
94
+ end
95
+
96
+ message = serialized_message(qm)
97
+
98
+ response = yield(message)
99
+
100
+ EventQ.log(:debug, "[#{self.class}] - Raised event. Message: #{message} | Type: #{event_type}.")
101
+
102
+ response.message_id
103
+ end
104
+
105
+ def serialized_message(queue_message)
106
+ serialization_provider = @serialization_manager.get_provider(EventQ::Configuration.serialization_provider)
107
+
108
+ serialization_provider.serialize(queue_message)
109
+ end
110
+
111
+ def topic_arn(event_type)
112
+ @client.sns_helper.get_topic_arn(event_type)
113
+ end
114
+
115
+ def sqs_message_body_for(payload_message)
116
+ JSON.dump(EventQ::Amazon::QueueWorker::MESSAGE => payload_message)
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EventQ
4
+ module Amazon
5
+ class QueueClient
6
+ def initialize(options = {})
7
+ invalid_keys = options.keys - [:sns_keep_alive_timeout, :sns_continue_timeout ]
8
+ raise(OptionParser::InvalidOption, invalid_keys) unless invalid_keys.empty?
9
+
10
+ @sns_keep_alive_timeout = options[:sns_keep_alive_timeout] || 30
11
+ @sns_continue_timeout = options[:sns_continue_timeout] || 15
12
+ end
13
+
14
+ # Returns the AWS SQS Client
15
+ def sqs
16
+ @sqs ||= sqs_client
17
+ end
18
+
19
+ # Returns the AWS SNS Client
20
+ def sns
21
+ @sns ||= sns_client
22
+ end
23
+
24
+ def sqs_helper
25
+ @sqs_helper ||= Amazon::SQS.new(sqs)
26
+ end
27
+
28
+ def sns_helper
29
+ @sns_helper ||= Amazon::SNS.new(sns)
30
+ end
31
+
32
+ private
33
+
34
+ def custom_endpoint(service)
35
+ aws_env = ENV["AWS_#{service.upcase}_ENDPOINT"].to_s.dup
36
+ aws_env.strip!
37
+ { endpoint: aws_env } unless aws_env.empty?
38
+ end
39
+
40
+ def sqs_client
41
+ options = custom_endpoint('sqs')
42
+ options.merge!(verify_checksums: false) if options
43
+
44
+ if options
45
+ Aws::SQS::Client.new(options)
46
+ else
47
+ Aws::SQS::Client.new
48
+ end
49
+ end
50
+
51
+ def sns_client
52
+ custom_endpoint('sns')
53
+ options = {
54
+ http_idle_timeout: @sns_keep_alive_timeout,
55
+ http_continue_timeout: @sns_continue_timeout
56
+ }
57
+ endpoint = custom_endpoint('sns')
58
+ options.merge!(endpoint) if endpoint
59
+
60
+ Aws::SNS::Client.new(options)
61
+ end
62
+ end
63
+ end
64
+ end