sqs_simplify 0.2.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: beb8c3464ca1465fe0dba02c9335ea205384e023648a569b7f896cd763630121
4
+ data.tar.gz: 571949adab26d1cf955941bd62b1a094b6919c6fdf7d4e32542d27d78d09569b
5
+ SHA512:
6
+ metadata.gz: c4652f7a1fc21ea9e865335154d3f9b8a69fdfe3258d31ba202c71f89befca0f6d04a3b74e98a401fa9222981c0f232f60f36a2ddd5e9f31ab785d2c57921399
7
+ data.tar.gz: c4e58d330eadb2d0c3468f4e44e5f2ae4a932a9a12af0846494f7fdc11e72ba5cd3c49b1628b57d5a5c956b4309810f49549a69d2a86e7580329c81b1a839da2
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /log
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ /.idea/*
12
+
13
+ # rspec failure tracking
14
+ .rspec_status
15
+ /.rakeTasks
16
+ /*.gem
17
+
18
+ .ruby-version
19
+ /Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format progress
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.5.1
6
+ before_install: gem install bundler -v 2.1.4
data/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0
4
+
5
+ - Consumer interrupts a message that runs out of time with `SqsSimplify::Errors::ExecutionExpired` instead of `throw`, so open database transactions roll back instead of being committed halfway.
6
+ - Consumer keeps the message (no delete) when the perform runs past its deadline, even if the application swallowed the timeout.
7
+ - `group_id` support for FIFO queues in `Scheduler` and `Message`.
8
+ - Worker options `worker_size` and `parallel_type` passed through the command line.
9
+ - `SqsSimplify::Command#daemonize` renamed to `#run`; the `daemons` dependency was removed.
10
+ - Dependencies relaxed to `aws-sdk-sqs ~> 1.0` and `parallel >= 1.20, < 3`; Ruby >= 3.0.
11
+
12
+ ## 0.1.0
13
+
14
+ - Initial version.
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in sqs_simplify.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
9
+ gem 'rspec', '~> 3.0'
10
+ gem 'rubocop', require: false
11
+
12
+ group :test do
13
+ gem 'simplecov', require: false
14
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 ralph baesso
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,383 @@
1
+ # SqsSimplify
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/sqs_simplify.svg)](https://badge.fury.io/rb/sqs_simplify)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Ruby](https://img.shields.io/badge/ruby-%3E%3D%203.0-red.svg)](https://www.ruby-lang.org)
6
+
7
+ A high-level Ruby DSL on top of `aws-sdk-sqs` for producing and consuming AWS SQS messages with minimal boilerplate.
8
+
9
+ It has 3 main roles:
10
+ * **SqsSimplify::Scheduler**: Sends messages to a queue.
11
+ * **SqsSimplify::Consumer**: Consumes messages from a queue.
12
+ * **SqsSimplify::Job**: Sends and consumes messages from a queue.
13
+
14
+ > 🇧🇷 Uma versão deste documento em português está disponível em [README.pt-br.md](README.pt-br.md).
15
+
16
+ ## Table of Contents
17
+
18
+ * [Requirements](#requirements)
19
+ * [Installation](#installation)
20
+ * [How to use](#how-to-use)
21
+ * [Initial Configuration](#1-initial-configuration)
22
+ * [Scheduler](#2-scheduler)
23
+ * [Consumer](#3-consumer)
24
+ * [Job](#4-job)
25
+ * [Configuration](#configuration)
26
+ * [Global Configuration](#1-global-configuration)
27
+ * [Hooks](#2-hooks)
28
+ * [Background Process](#background-process)
29
+ * [Advanced features](#advanced-features)
30
+ * [Development](#development)
31
+ * [Contributing](#contributing)
32
+ * [License](#license)
33
+
34
+ ## Requirements
35
+
36
+ * Ruby `>= 3.0.0`
37
+ * Runtime dependencies (installed automatically with the gem):
38
+ * [`aws-sdk-sqs`](https://rubygems.org/gems/aws-sdk-sqs) `~> 1.116`
39
+ * [`parallel`](https://rubygems.org/gems/parallel) `~> 2.1`
40
+
41
+ You also need valid AWS credentials with access to SQS.
42
+
43
+ ## Installation
44
+
45
+ Add this line to your application's Gemfile:
46
+
47
+ ```ruby
48
+ gem 'sqs_simplify'
49
+ ```
50
+
51
+ And then execute:
52
+
53
+ $ bundle install
54
+
55
+ Or install it yourself as:
56
+
57
+ $ gem install sqs_simplify
58
+ ___
59
+
60
+ ## How to use
61
+ ### 1. Initial Configuration
62
+
63
+ Create a configuration file to be loaded when the application starts.
64
+
65
+ Example: *sqs_simplify.rb*
66
+
67
+ If it is a **Rails** application, create it at *config/initializers/sqs_simplify.rb*.
68
+
69
+ In this file you can configure your AWS credentials and other customizations.
70
+
71
+ ```ruby
72
+ # sqs_simplify.rb
73
+
74
+ SqsSimplify.configure do |config|
75
+ config.access_key_id = ENV['AWS_ACCESS_KEY_ID']
76
+ config.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
77
+ config.region = 'us-east-1'
78
+
79
+ config.queue_prefix = Rails.env # optional
80
+ config.queue_suffix = 'my_application_name' # optional
81
+ end
82
+ ```
83
+ ___
84
+
85
+
86
+ ### 2. Scheduler
87
+
88
+ The Scheduler component is responsible for sending messages to the SQS queue.
89
+
90
+ Its main focus is using a queue as a bus between two distinct applications.
91
+
92
+ For example: application **A** has a Scheduler that sends a message to the SQS queue, but the one that will consume this message is application **B**.
93
+
94
+ ```ruby
95
+ # app/jobs/my_scheduler
96
+
97
+ class MyScheduler < SqsSimplify::Scheduler
98
+ end
99
+
100
+
101
+ # app/model/wheel_factory.rb
102
+
103
+ class WheelFactory
104
+ def send_now
105
+ message = { wheels: ['back_wheel', 'front_wheel'], type: 'motorcycle' }
106
+ MyScheduler.send_message(message: message)
107
+ end
108
+
109
+ def send_later(delay)
110
+ message = { wheels: ['back_wheel', 'front_wheel'], type: 'motorcycle' }
111
+ MyScheduler.send_message(message: message, after: delay)
112
+ end
113
+ end
114
+
115
+
116
+ wheel_factory = WheelFactory.new
117
+
118
+ # run now
119
+ wheel_factory.send_now # "8685d169-f4a0-476b-b970-39ee055f957b"
120
+
121
+ # run after 2 minutes
122
+ wheel_factory.send_later(120) # "5ebd6a74-8571-43e2-a9c8-7866b7598765"
123
+
124
+ ```
125
+
126
+ #### `group_id`
127
+
128
+ The `group_id` parameter is sent to SQS as `message_group_id`. Provide it in
129
+ `send_message`:
130
+
131
+ ```ruby
132
+ MyScheduler.send_message(message: message, group_id: 'tenant-123')
133
+ ```
134
+
135
+ Its meaning depends on the queue type:
136
+
137
+ * **FIFO queues**: SQS requires `message_group_id`. Messages with the same
138
+ `group_id` are processed in order (FIFO).
139
+ * **Standard queues**: the `message_group_id` is used as a *tenant* identifier
140
+ for the [fair queues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-fair-queues.html)
141
+ feature, which mitigates the *noisy neighbor* impact in multi-tenant queues.
142
+ Here it does **not** guarantee ordering — it only groups messages by tenant.
143
+
144
+ If omitted (`nil`), no `message_group_id` is sent.
145
+
146
+ ### 3. Consumer
147
+
148
+ The Consumer component is responsible for consuming messages from the SQS queue.
149
+
150
+ Its main focus is also using a queue as a bus between two distinct applications.
151
+
152
+ For example: application **B** has a Consumer that requests messages from the SQS queue that were sent by application **A**.
153
+
154
+ ```ruby
155
+ # app/jobs/motorcycle_assembler.rb
156
+
157
+ class MotorcycleAssembler < SqsSimplify::Consumer
158
+
159
+ def perform
160
+ # your logic here
161
+ # your object has "message" method with data of sqs_message
162
+ p message # {:wheels=>["back_wheel", "front_wheel"], :type=>"motorcycle"}
163
+ end
164
+
165
+ end
166
+
167
+ ```
168
+
169
+
170
+ ### 4. Job
171
+
172
+ The Job component is responsible for sending and consuming messages from the SQS queue within the same application.
173
+
174
+ Unlike the other components, its focus is **not** on using a queue as a bus.
175
+
176
+ For example: your application has a **Report** class that generates a report.
177
+ This processing takes a long time to run.
178
+ So you can schedule its execution for later.
179
+
180
+ The business method **must** be named `perform`.
181
+
182
+ ```ruby
183
+ # app/jobs/report.rb
184
+
185
+ class Report < SqsSimplify::Job
186
+
187
+ def perform(list)
188
+ # your logic here
189
+ PersistReport.save(list)
190
+ end
191
+
192
+ end
193
+
194
+ list = # many data
195
+
196
+ # enqueue for later execution
197
+ Report.perform_later(list) # "76107a55-43d9-4f2e-b449-02c329a51692"
198
+
199
+ # enqueue with a 180 second delay
200
+ Report.new_job(after: 180).perform_later(list) # "be6837d5-c11f-495c-a03e-cb093011f1d0"
201
+
202
+ # run inline, without enqueuing
203
+ # note: it will not be scheduled
204
+ Report.perform(list) # :executed
205
+ ```
206
+
207
+ ___
208
+
209
+ ## Configuration
210
+
211
+ ### 1. Global Configuration
212
+
213
+ #### SqsSimplify
214
+ Every configuration made on the SqsSimplify class will be applied to all components.
215
+
216
+ Example:
217
+
218
+ ```ruby
219
+ # sqs_simplify.rb
220
+
221
+ SqsSimplify.configure do |config|
222
+ config.access_key_id = ENV['AWS_ACCESS_KEY_ID']
223
+ config.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
224
+ config.region = 'us-east-2'
225
+
226
+ config.queue_prefix = 'production'
227
+ end
228
+ ```
229
+
230
+ With this configuration all components — Scheduler, Consumer and Job — will share the same configuration.
231
+
232
+ All of them will have access to the SQS queues in *us-east-2*
233
+
234
+ All of them will have the *production* prefix
235
+
236
+
237
+ ```ruby
238
+
239
+ class MyScheduler < SqsSimplify::Scheduler
240
+
241
+ end
242
+
243
+ class MyConsumer < SqsSimplify::Consumer
244
+
245
+ end
246
+
247
+ class MyJob < SqsSimplify::Job
248
+
249
+ end
250
+
251
+ # same prefix
252
+ MyScheduler.queue_name # "production_my_scheduler"
253
+ MyConsumer.queue_name # "production_my_consumer"
254
+ MyJob.queue_name # "production_my_job"
255
+
256
+ ```
257
+
258
+ ### 2. Hooks
259
+
260
+ **resolver_exception:** Invoked whenever an **Exception** occurs in your application.
261
+ It provides two parameters:
262
+ * the **first parameter** is an **Exception**.
263
+ * the **second parameter** may vary depending on the component and where the **Exception** occurred.
264
+
265
+ **message_not_deleted:** Invoked when a Job or Consumer picks up a message from the SQS queue but is unable to delete it.
266
+ There are two main reasons for this to happen:
267
+ * **Exception**: when an **Exception** occurs. Note: the **resolver_exception** hook will also be invoked.
268
+ * **Default visibility timeout**: the message was not processed within the defined time.
269
+
270
+ ```ruby
271
+ # sqs_simplify.rb
272
+
273
+ SqsSimplify.configure do |config|
274
+ config.hooks.resolver_exception do |exception, args|
275
+ logger.info "Exception => #{exception.message}, args => #{args}"
276
+ end
277
+
278
+ config.hooks.message_not_deleted do |consumer|
279
+ logger.info "Consumer => #{consumer}"
280
+ end
281
+ end
282
+ ```
283
+
284
+ ___
285
+
286
+ ## Background Process
287
+ ### 1. Setup
288
+ To run the consuming process you must create a script file.
289
+ The `run` method runs a foreground loop that consumes the queues until it
290
+ receives `SIGINT` (Ctrl+C) — it does not daemonize the process.
291
+ Example of a script file named *sqs_simplify*
292
+
293
+ ```ruby
294
+ #!/usr/bin/env ruby
295
+
296
+ require 'sqs_simplify/command'
297
+ SqsSimplify::Command.new(ARGV).run
298
+ ```
299
+
300
+ For a Rails project you can load the application before invoking the GEM.
301
+ Example of a script file named *bin/sqs_simplify*
302
+ ```ruby
303
+ #!/usr/bin/env ruby
304
+
305
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
306
+ require 'sqs_simplify/command'
307
+ SqsSimplify::Command.new(ARGV).run
308
+ ```
309
+
310
+ And you must grant execution permission.
311
+ ````bash
312
+ $ chmod +x sqs_simplify
313
+ ````
314
+
315
+ ### 2. Commands
316
+ To see the command options, run it in the file's directory:
317
+
318
+ ````bash
319
+ $ sqs_simplify -h
320
+ Usage: sqs_simplify [options]
321
+ -h, --help Show help
322
+ -n, --number_of_workers=workers Number of unique workers to spawn
323
+ -e, --environment=environment Environment
324
+ --queues=queues queues that will be consumed
325
+ --priority with priority in the queues
326
+ -f, --fork parallel in processes
327
+ -t, --thread parallel in threads
328
+
329
+
330
+ ````
331
+
332
+ ___
333
+
334
+ ## Advanced features
335
+
336
+ Beyond the basics above, the gem also supports:
337
+
338
+ * **`map_queue(nickname, &block)`** — route a single Scheduler to alternate queues
339
+ dynamically (`SqsSimplify::Scheduler`).
340
+ * **Per-call destination override** — pass `queue_url:` to `send_message` to send a
341
+ message to a specific queue at call time.
342
+ * **Class-level `set` DSL** — override per-class settings such as the queue name,
343
+ visibility timeout, serialization (`dump_message`/`load_message`) and more, e.g.
344
+ `set :queue_name, 'custom_name'`.
345
+ * **Automatic dead-letter queues** — every queue gets a paired `<name>_dead`
346
+ dead-letter queue.
347
+ * **Additional hooks** — besides `resolver_exception` and `message_not_deleted`, the
348
+ pipeline also supports `before`/`after` (`:each` / `:all`) and `around` hooks.
349
+ * **Testing without AWS** — set `config.faker = true` to use the in-memory
350
+ `FakerClient`, or `config.stub_responses = true` to stub the `aws-sdk-sqs` client.
351
+
352
+ ## Development
353
+
354
+ After checking out the repo, install dependencies and run the test suite:
355
+
356
+ ```bash
357
+ bin/setup # install dependencies
358
+ bundle exec rake spec # run the full test suite
359
+ bundle exec rubocop # lint
360
+ bin/console # interactive prompt to experiment
361
+ ```
362
+
363
+ Tests run against an in-memory fake SQS client, so no real AWS access is required.
364
+
365
+ To install this gem onto your local machine, run `bundle exec rake install`. To
366
+ release a new version, update the version number in `lib/sqs_simplify/version.rb`,
367
+ then run `bundle exec rake release`.
368
+
369
+ ## Contributing
370
+
371
+ Bug reports and pull requests are welcome on GitHub at
372
+ https://github.com/ralphsbaesso/sqs_simplify. To contribute:
373
+
374
+ 1. Fork the repository.
375
+ 2. Create a feature branch (`git checkout -b my-feature`).
376
+ 3. Commit your changes and make sure the tests (`bundle exec rake spec`) and linter
377
+ (`bundle exec rubocop`) pass.
378
+ 4. Open a pull request.
379
+
380
+
381
+ ## License
382
+
383
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).