freddy 1.6.0 → 2.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 +4 -4
- data/.github/workflows/ci.yml +31 -0
- data/.rubocop.yml +9 -28
- data/.ruby-gemset +1 -1
- data/.ruby-version +1 -1
- data/Gemfile +3 -4
- data/README.md +49 -18
- data/freddy.gemspec +12 -18
- data/lib/freddy/adapters/bunny_adapter.rb +20 -3
- data/lib/freddy/adapters.rb +3 -28
- data/lib/freddy/consumers/respond_to_consumer.rb +3 -13
- data/lib/freddy/consumers/response_consumer.rb +2 -4
- data/lib/freddy/consumers/tap_into_consumer.rb +25 -34
- data/lib/freddy/consumers.rb +1 -1
- data/lib/freddy/delivery.rb +45 -13
- data/lib/freddy/encoding.rb +27 -0
- data/lib/freddy/payload.rb +4 -34
- data/lib/freddy/producers/reply_producer.rb +12 -5
- data/lib/freddy/producers/send_and_forget_producer.rb +9 -12
- data/lib/freddy/producers/send_and_wait_response_producer.rb +19 -33
- data/lib/freddy/producers.rb +1 -1
- data/lib/freddy/request_manager.rb +1 -9
- data/lib/freddy/tracing.rb +37 -0
- data/lib/freddy/version.rb +5 -0
- data/lib/freddy.rb +18 -20
- data/spec/.rubocop.yml +26 -0
- data/spec/freddy/error_response_spec.rb +6 -6
- data/spec/freddy/freddy_spec.rb +23 -0
- data/spec/freddy/payload_spec.rb +25 -16
- data/spec/integration/concurrency_spec.rb +8 -12
- data/spec/integration/tap_into_with_group_spec.rb +15 -0
- data/spec/integration/tracing_spec.rb +45 -32
- data/spec/spec_helper.rb +5 -13
- metadata +47 -20
- data/.npmignore +0 -8
- data/.travis.yml +0 -13
- data/lib/freddy/adapters/march_hare_adapter.rb +0 -64
- data/lib/freddy/trace_carrier.rb +0 -28
- data/spec/freddy/trace_carrier_spec.rb +0 -56
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5ccc6957f658f70ad21c03dbdd3a1477ae0e84cbb3c91c18b127fea5b02c2e67
|
|
4
|
+
data.tar.gz: d6f766526c1d60f8f324846cb92de6c284e3f22357545fc0590bba93ab8726e7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7b3a9b5de12182558c09cad3f029fec1ab221688a56c6473d6b7fe110d55ea3d0fcf6f31106798190f54ef4ba8a362928d82c983eca23c8a7b6c32cede406e18
|
|
7
|
+
data.tar.gz: 3f0e57546ad9671ec00381a4da2b12c2e574d4a2d807a9929d65d2f81887dd3318f94a7a3bc4a4a388b4745a9576ae3648acebe6ecd634b70a1d2e605a6072e1
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Ruby
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ master ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ master ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
ruby-version: ['2.6']
|
|
15
|
+
services:
|
|
16
|
+
rabbitmq:
|
|
17
|
+
image: rabbitmq
|
|
18
|
+
ports:
|
|
19
|
+
- 5672:5672
|
|
20
|
+
options: --health-cmd "rabbitmqctl node_health_check" --health-interval 10s --health-timeout 5s --health-retries 5
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v2
|
|
23
|
+
with:
|
|
24
|
+
submodules: true
|
|
25
|
+
- name: Set up Ruby
|
|
26
|
+
uses: ruby/setup-ruby@v1
|
|
27
|
+
with:
|
|
28
|
+
ruby-version: ${{ matrix.ruby-version }}
|
|
29
|
+
bundler-cache: true
|
|
30
|
+
- name: Run lint & tests
|
|
31
|
+
run: bundle exec rake
|
data/.rubocop.yml
CHANGED
|
@@ -1,39 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
AllCops:
|
|
2
|
+
NewCops: enable
|
|
3
|
+
SuggestExtensions: false
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
Enabled: no
|
|
5
|
-
|
|
6
|
-
Metrics/BlockLength:
|
|
7
|
-
Enabled: no
|
|
8
|
-
|
|
9
|
-
Metrics/LineLength:
|
|
5
|
+
Layout/LineLength:
|
|
10
6
|
Max: 120
|
|
11
7
|
|
|
12
|
-
|
|
13
|
-
Enabled: no
|
|
14
|
-
|
|
15
|
-
Style/Documentation:
|
|
16
|
-
Enabled: no
|
|
17
|
-
|
|
18
|
-
RSpec/ExampleLength:
|
|
19
|
-
Enabled: no
|
|
20
|
-
|
|
21
|
-
RSpec/MultipleExpectations:
|
|
8
|
+
Lint/EmptyBlock:
|
|
22
9
|
Enabled: no
|
|
23
10
|
|
|
24
|
-
|
|
25
|
-
Enabled: no
|
|
26
|
-
|
|
27
|
-
RSpec/VerifiedDoubles:
|
|
11
|
+
Metrics/AbcSize:
|
|
28
12
|
Enabled: no
|
|
29
13
|
|
|
30
|
-
|
|
14
|
+
Metrics/BlockLength:
|
|
31
15
|
Enabled: no
|
|
32
16
|
|
|
33
|
-
|
|
17
|
+
Metrics/MethodLength:
|
|
34
18
|
Enabled: no
|
|
35
19
|
|
|
36
|
-
|
|
20
|
+
Style/Documentation:
|
|
37
21
|
Enabled: no
|
|
38
22
|
|
|
39
23
|
Style/FrozenStringLiteralComment:
|
|
@@ -42,8 +26,5 @@ Style/FrozenStringLiteralComment:
|
|
|
42
26
|
Include:
|
|
43
27
|
- 'lib/**/*'
|
|
44
28
|
|
|
45
|
-
Performance/TimesMap:
|
|
46
|
-
Enabled: no
|
|
47
|
-
|
|
48
29
|
Naming/FileName:
|
|
49
30
|
Enabled: no
|
data/.ruby-gemset
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
freddy
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.6
|
data/Gemfile
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
source 'https://rubygems.org'
|
|
2
2
|
|
|
3
|
-
gem 'codeclimate-test-reporter'
|
|
4
3
|
gem 'hamster', '~> 3.0'
|
|
5
|
-
gem '
|
|
4
|
+
gem 'opentelemetry-sdk', '~> 1.0.0.rc3'
|
|
6
5
|
gem 'pry'
|
|
7
6
|
gem 'rspec'
|
|
8
|
-
gem 'rubocop', '~>
|
|
9
|
-
gem 'rubocop-rspec', '~>
|
|
7
|
+
gem 'rubocop', '~> 1.19'
|
|
8
|
+
gem 'rubocop-rspec', '~> 2.4'
|
|
10
9
|
|
|
11
10
|
gemspec
|
data/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# Messaging API supporting acknowledgements and request-response
|
|
2
2
|
|
|
3
|
-
[](https://codeclimate.com/github/salemove/freddy)
|
|
5
|
-
[](https://codeclimate.com/github/salemove/freddy/coverage)
|
|
3
|
+
[](https://github.com/salemove/freddy/actions/workflows/ci.yml?query=branch%3Amaster)
|
|
6
4
|
|
|
7
5
|
## Setup
|
|
8
6
|
|
|
@@ -24,39 +22,60 @@ These message queues have been tested and are working with Freddy. Other queues
|
|
|
24
22
|
### Simple delivery
|
|
25
23
|
|
|
26
24
|
#### Send and forget
|
|
25
|
+
|
|
27
26
|
Sends a `message` to the given `destination`. If there is no consumer then the
|
|
28
27
|
message stays in the queue until somebody consumes it.
|
|
28
|
+
|
|
29
29
|
```ruby
|
|
30
|
-
|
|
30
|
+
freddy.deliver(destination, message)
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
#### Expiring messages
|
|
34
|
+
|
|
34
35
|
Sends a `message` to the given `destination`. If nobody consumes the message in
|
|
35
36
|
`timeout` seconds then the message is discarded. This is useful for showing
|
|
36
37
|
notifications that must happen in a certain timeframe but where we don't really
|
|
37
38
|
care if it reached the destination or not.
|
|
39
|
+
|
|
38
40
|
```ruby
|
|
39
41
|
freddy.deliver(destination, message, timeout: 5)
|
|
40
42
|
```
|
|
41
43
|
|
|
44
|
+
#### Compressed messages
|
|
45
|
+
|
|
46
|
+
Sends a `message` to the given `destination`. If `compress` is passed as an option parameter, it will compress the
|
|
47
|
+
payload according to the algorithm provided. Currently the `zlib` algorithm is implemented to compress the payload.
|
|
48
|
+
The message heading specify the `content-encoding` indicating the compression algorithm used.
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
freddy.deliver(destination, message, compress: 'zlib')
|
|
52
|
+
```
|
|
53
|
+
|
|
42
54
|
### Request delivery
|
|
55
|
+
|
|
43
56
|
#### Expiring messages
|
|
57
|
+
|
|
44
58
|
Sends a `message` to the given `destination`. Has a default timeout of 3 and
|
|
45
59
|
discards the message from the queue if a response hasn't been returned in that
|
|
46
60
|
time.
|
|
61
|
+
|
|
47
62
|
```ruby
|
|
48
63
|
response = freddy.deliver_with_response(destination, message)
|
|
49
64
|
```
|
|
50
65
|
|
|
51
66
|
#### Persistant messages
|
|
67
|
+
|
|
52
68
|
Sends a `message` to the given `destination`. Keeps the message in the queue if
|
|
53
69
|
a timeout occurs.
|
|
70
|
+
|
|
54
71
|
```ruby
|
|
55
72
|
response = freddy.deliver_with_response(destination, message, timeout: 4, delete_on_timeout: false)
|
|
56
73
|
```
|
|
57
74
|
|
|
58
75
|
#### Errors
|
|
76
|
+
|
|
59
77
|
`deliver_with_response` raises an error if an error is returned. This can be handled by rescuing from `Freddy::InvalidRequestError` and `Freddy::TimeoutError` as:
|
|
78
|
+
|
|
60
79
|
```ruby
|
|
61
80
|
begin
|
|
62
81
|
response = freddy.deliver_with_response 'Q', {}
|
|
@@ -68,6 +87,7 @@ rescue Freddy::TimeoutError => e
|
|
|
68
87
|
```
|
|
69
88
|
|
|
70
89
|
## Responding to messages
|
|
90
|
+
|
|
71
91
|
```ruby
|
|
72
92
|
freddy.respond_to destination do |message, msg_handler|
|
|
73
93
|
# ...
|
|
@@ -75,8 +95,9 @@ end
|
|
|
75
95
|
```
|
|
76
96
|
|
|
77
97
|
The callback is called with 2 arguments
|
|
78
|
-
|
|
79
|
-
|
|
98
|
+
|
|
99
|
+
* the parsed message (note that in the message all keys are symbolized)
|
|
100
|
+
* the `MessageHandler` (described further down)
|
|
80
101
|
|
|
81
102
|
## The MessageHandler
|
|
82
103
|
|
|
@@ -84,17 +105,20 @@ When responding to messages the MessageHandler is given as the second argument.
|
|
|
84
105
|
|
|
85
106
|
The following operations are supported:
|
|
86
107
|
|
|
87
|
-
|
|
108
|
+
* responding with a successful response
|
|
109
|
+
|
|
88
110
|
```ruby
|
|
89
111
|
msg_handler.success(response = nil)
|
|
90
112
|
```
|
|
91
113
|
|
|
92
|
-
|
|
114
|
+
* responding with an error response
|
|
115
|
+
|
|
93
116
|
```ruby
|
|
94
117
|
msg_handler.error(error: "Couldn't process message")
|
|
95
118
|
```
|
|
96
119
|
|
|
97
120
|
## Tapping into messages
|
|
121
|
+
|
|
98
122
|
When it's necessary to receive messages but not consume them, consider tapping.
|
|
99
123
|
|
|
100
124
|
```ruby
|
|
@@ -121,40 +145,47 @@ freddy.tap_into "somebody.*.love"
|
|
|
121
145
|
|
|
122
146
|
receives messages that are delivered to `somebody.to.love` but doesn't receive messages delivered to `someboy.not.to.love`
|
|
123
147
|
|
|
148
|
+
It is also possible to tap using multiple patterns:
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
freddy.tap_into(['user.created', 'user.deleted'], group: 'user-event') do
|
|
152
|
+
# This processes events from both user.created topic and user.deleted topic.
|
|
153
|
+
# It also groups them into one queue called 'user-event'. This ensures that
|
|
154
|
+
# only one listener within a group process a particular event.
|
|
155
|
+
end
|
|
156
|
+
```
|
|
157
|
+
|
|
124
158
|
## The ResponderHandler
|
|
125
159
|
|
|
126
160
|
When responding to a message or tapping the ResponderHandler is returned.
|
|
161
|
+
|
|
127
162
|
```ruby
|
|
128
163
|
responder_handler = freddy.respond_to ....
|
|
129
164
|
```
|
|
130
165
|
|
|
131
166
|
The following operations are supported:
|
|
132
167
|
|
|
133
|
-
|
|
168
|
+
* stop responding
|
|
169
|
+
|
|
134
170
|
```ruby
|
|
135
171
|
responder_handler.shutdown
|
|
136
172
|
```
|
|
137
173
|
|
|
138
174
|
## Request Tracing
|
|
139
175
|
|
|
140
|
-
Freddy supports [
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
Current trace can be accessed through a thread-local variable `OpenTracing.active_span`. Calling `deliver` or `deliver_with_response` will pass trace context to down-stream services.
|
|
176
|
+
Freddy supports [OpenTelemetry API|https://github.com/open-telemetry/opentelemetry-ruby].
|
|
177
|
+
The trace information is automatically passed through `deliver`,
|
|
178
|
+
`deliver_with_response`, `respond_to` and `tap_into` calls.
|
|
146
179
|
|
|
147
|
-
|
|
180
|
+
This is not compatible with `opentelemetry-instrumentation-bunny` library.
|
|
148
181
|
|
|
149
182
|
## Notes about concurrency
|
|
150
183
|
|
|
151
184
|
*freddy* uses a thread pool to run concurrent responders. The thread pool is unique for each *tap_into* and *respond_to* responder. Thread pool size can be configured by passing the configuration option *max_concurrency*. Its default value is 4. e.g. If your application has 2 *respond_to* responders and 1 *tap_into* responder with *max_concurrency* set to 3 then your application may process up to 9 messages in parallel.
|
|
152
185
|
|
|
153
|
-
|
|
154
186
|
Note that while it is possible to use *deliver_with_response* inside a *respond_to* block,
|
|
155
187
|
it is not possible to use another *respond_to* block inside a different *respond_to* block.
|
|
156
188
|
|
|
157
|
-
|
|
158
189
|
Note also that other configuration options for freddy users
|
|
159
190
|
such as pool sizes for DB connections need to match or exceed *max_concurrency*
|
|
160
191
|
to avoid running out of resources.
|
data/freddy.gemspec
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
|
|
2
1
|
lib = File.expand_path('lib', __dir__)
|
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
+
require 'freddy/version'
|
|
4
4
|
|
|
5
5
|
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
'freddy'
|
|
10
|
-
end
|
|
11
|
-
spec.version = '1.6.0'
|
|
12
|
-
spec.authors = ['Salemove TechMovers']
|
|
6
|
+
spec.name = 'freddy'
|
|
7
|
+
spec.version = Freddy::VERSION
|
|
8
|
+
spec.authors = ['Glia TechMovers']
|
|
13
9
|
spec.email = ['techmovers@salemove.com']
|
|
14
10
|
spec.description = 'Messaging API'
|
|
15
11
|
spec.summary = 'API for inter-application messaging supporting acknowledgements and request-response'
|
|
16
|
-
spec.license = '
|
|
12
|
+
spec.license = 'MIT'
|
|
13
|
+
spec.homepage = 'https://github.com/salemove/freddy'
|
|
14
|
+
spec.required_ruby_version = '>= 2.6'
|
|
17
15
|
|
|
18
16
|
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
|
19
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
@@ -23,14 +21,10 @@ Gem::Specification.new do |spec|
|
|
|
23
21
|
spec.add_development_dependency 'bundler'
|
|
24
22
|
spec.add_development_dependency 'rake'
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
spec.add_dependency 'bunny', '~> 2.11'
|
|
31
|
-
spec.add_dependency 'oj', '~> 3.6'
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
spec.add_dependency 'opentracing', '~> 0.4'
|
|
24
|
+
spec.add_dependency 'bunny', '~> 2.11'
|
|
25
|
+
spec.add_dependency 'oj', '~> 3.6'
|
|
26
|
+
spec.add_dependency 'opentelemetry-api', '~> 1.0.0.rc3'
|
|
27
|
+
spec.add_dependency 'opentelemetry-semantic_conventions', '~> 1.0'
|
|
35
28
|
spec.add_dependency 'thread', '~> 0.1'
|
|
29
|
+
spec.add_dependency 'zlib', '~> 1.1'
|
|
36
30
|
end
|
|
@@ -47,12 +47,29 @@ class Freddy
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
class Queue
|
|
50
|
+
class Queue
|
|
51
|
+
def initialize(queue)
|
|
52
|
+
@queue = queue
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def bind(*args)
|
|
56
|
+
@queue.bind(*args)
|
|
57
|
+
self
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def name
|
|
61
|
+
@queue.name
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def message_count
|
|
65
|
+
@queue.message_count
|
|
66
|
+
end
|
|
67
|
+
|
|
51
68
|
def subscribe(manual_ack: false)
|
|
52
69
|
@queue.subscribe(manual_ack: manual_ack) do |info, properties, payload|
|
|
53
|
-
parsed_payload = Payload.parse(payload)
|
|
70
|
+
parsed_payload = Payload.parse(payload, properties[:content_encoding])
|
|
54
71
|
delivery = Delivery.new(
|
|
55
|
-
parsed_payload, properties, info.routing_key, info.delivery_tag
|
|
72
|
+
parsed_payload, properties, info.routing_key, info.delivery_tag, info.exchange
|
|
56
73
|
)
|
|
57
74
|
yield(delivery)
|
|
58
75
|
end
|
data/lib/freddy/adapters.rb
CHANGED
|
@@ -1,36 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'adapters/bunny_adapter'
|
|
4
|
+
|
|
3
5
|
class Freddy
|
|
4
6
|
module Adapters
|
|
5
7
|
def self.determine
|
|
6
|
-
|
|
7
|
-
require_relative 'adapters/march_hare_adapter'
|
|
8
|
-
MarchHareAdapter
|
|
9
|
-
else
|
|
10
|
-
require_relative 'adapters/bunny_adapter'
|
|
11
|
-
BunnyAdapter
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
module Shared
|
|
16
|
-
class Queue
|
|
17
|
-
def initialize(queue)
|
|
18
|
-
@queue = queue
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def bind(*args)
|
|
22
|
-
@queue.bind(*args)
|
|
23
|
-
self
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def name
|
|
27
|
-
@queue.name
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def message_count
|
|
31
|
-
@queue.message_count
|
|
32
|
-
end
|
|
33
|
-
end
|
|
8
|
+
BunnyAdapter
|
|
34
9
|
end
|
|
35
10
|
end
|
|
36
11
|
end
|
|
@@ -35,21 +35,11 @@ class Freddy
|
|
|
35
35
|
|
|
36
36
|
def process_message(delivery)
|
|
37
37
|
@consume_thread_pool.process do
|
|
38
|
-
|
|
39
|
-
scope = delivery.build_trace("freddy:respond:#{@destination}",
|
|
40
|
-
tags: {
|
|
41
|
-
'peer.address' => "#{@destination}:#{delivery.payload[:type]}",
|
|
42
|
-
'component' => 'freddy',
|
|
43
|
-
'span.kind' => 'server', # RPC
|
|
44
|
-
'message_bus.destination' => @destination,
|
|
45
|
-
'message_bus.correlation_id' => delivery.correlation_id
|
|
46
|
-
})
|
|
47
|
-
|
|
38
|
+
delivery.in_span do
|
|
48
39
|
yield(delivery)
|
|
49
|
-
ensure
|
|
50
|
-
@channel.acknowledge(delivery.tag, false)
|
|
51
|
-
scope.close
|
|
52
40
|
end
|
|
41
|
+
ensure
|
|
42
|
+
@channel.acknowledge(delivery.tag, false)
|
|
53
43
|
end
|
|
54
44
|
end
|
|
55
45
|
end
|
|
@@ -7,11 +7,9 @@ class Freddy
|
|
|
7
7
|
@logger = logger
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
def consume(_channel, queue)
|
|
10
|
+
def consume(_channel, queue, &block)
|
|
11
11
|
@logger.debug "Consuming messages on #{queue.name}"
|
|
12
|
-
queue.subscribe
|
|
13
|
-
yield(delivery)
|
|
14
|
-
end
|
|
12
|
+
queue.subscribe(&block)
|
|
15
13
|
end
|
|
16
14
|
end
|
|
17
15
|
end
|