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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +31 -0
  3. data/.rubocop.yml +9 -28
  4. data/.ruby-gemset +1 -1
  5. data/.ruby-version +1 -1
  6. data/Gemfile +3 -4
  7. data/README.md +49 -18
  8. data/freddy.gemspec +12 -18
  9. data/lib/freddy/adapters/bunny_adapter.rb +20 -3
  10. data/lib/freddy/adapters.rb +3 -28
  11. data/lib/freddy/consumers/respond_to_consumer.rb +3 -13
  12. data/lib/freddy/consumers/response_consumer.rb +2 -4
  13. data/lib/freddy/consumers/tap_into_consumer.rb +25 -34
  14. data/lib/freddy/consumers.rb +1 -1
  15. data/lib/freddy/delivery.rb +45 -13
  16. data/lib/freddy/encoding.rb +27 -0
  17. data/lib/freddy/payload.rb +4 -34
  18. data/lib/freddy/producers/reply_producer.rb +12 -5
  19. data/lib/freddy/producers/send_and_forget_producer.rb +9 -12
  20. data/lib/freddy/producers/send_and_wait_response_producer.rb +19 -33
  21. data/lib/freddy/producers.rb +1 -1
  22. data/lib/freddy/request_manager.rb +1 -9
  23. data/lib/freddy/tracing.rb +37 -0
  24. data/lib/freddy/version.rb +5 -0
  25. data/lib/freddy.rb +18 -20
  26. data/spec/.rubocop.yml +26 -0
  27. data/spec/freddy/error_response_spec.rb +6 -6
  28. data/spec/freddy/freddy_spec.rb +23 -0
  29. data/spec/freddy/payload_spec.rb +25 -16
  30. data/spec/integration/concurrency_spec.rb +8 -12
  31. data/spec/integration/tap_into_with_group_spec.rb +15 -0
  32. data/spec/integration/tracing_spec.rb +45 -32
  33. data/spec/spec_helper.rb +5 -13
  34. metadata +47 -20
  35. data/.npmignore +0 -8
  36. data/.travis.yml +0 -13
  37. data/lib/freddy/adapters/march_hare_adapter.rb +0 -64
  38. data/lib/freddy/trace_carrier.rb +0 -28
  39. data/spec/freddy/trace_carrier_spec.rb +0 -56
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2c342119c1a4c330673258a8c5dbeb5d33ea15bc06ddbe261e1cfb8485829fe
4
- data.tar.gz: a66de9b5b4f97ff58e1f8a321daa5846526a68c41fb4d7e4121d0c90fed55101
3
+ metadata.gz: 5ccc6957f658f70ad21c03dbdd3a1477ae0e84cbb3c91c18b127fea5b02c2e67
4
+ data.tar.gz: d6f766526c1d60f8f324846cb92de6c284e3f22357545fc0590bba93ab8726e7
5
5
  SHA512:
6
- metadata.gz: fa9f61272f5f792c2e944ad39d2604693a14950d0a7bef43f3fcba8d3865ce0ff992877bc27427d66aa29314e1b6ae1fc6acde15e1f513169fbe49a1cc1c496a
7
- data.tar.gz: '0678e4121e3eaaa5669d5d5ef4963c91a31ace9f605ecaf1050136f98a3df1c3b6e24b6709e5abaed8b530c21f89695b18d6ed7c5ab7f6543e47e254abd01b18'
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
- require: rubocop-rspec
1
+ AllCops:
2
+ NewCops: enable
3
+ SuggestExtensions: false
2
4
 
3
- Metrics/AbcSize:
4
- Enabled: no
5
-
6
- Metrics/BlockLength:
7
- Enabled: no
8
-
9
- Metrics/LineLength:
5
+ Layout/LineLength:
10
6
  Max: 120
11
7
 
12
- Metrics/MethodLength:
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
- RSpec/MessageSpies:
25
- Enabled: no
26
-
27
- RSpec/VerifiedDoubles:
11
+ Metrics/AbcSize:
28
12
  Enabled: no
29
13
 
30
- RSpec/InstanceVariable:
14
+ Metrics/BlockLength:
31
15
  Enabled: no
32
16
 
33
- RSpec/NestedGroups:
17
+ Metrics/MethodLength:
34
18
  Enabled: no
35
19
 
36
- RSpec/DescribeClass:
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
- sm-messaging
1
+ freddy
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.4
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 'opentracing_test_tracer', '~> 0.1'
4
+ gem 'opentelemetry-sdk', '~> 1.0.0.rc3'
6
5
  gem 'pry'
7
6
  gem 'rspec'
8
- gem 'rubocop', '~> 0.54.0'
9
- gem 'rubocop-rspec', '~> 1.24.0'
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
- [![Build Status](https://travis-ci.org/salemove/freddy.svg?branch=master)](https://travis-ci.org/salemove/freddy)
4
- [![Code Climate](https://codeclimate.com/github/salemove/freddy/badges/gpa.svg)](https://codeclimate.com/github/salemove/freddy)
5
- [![Test Coverage](https://codeclimate.com/github/salemove/freddy/badges/coverage.svg)](https://codeclimate.com/github/salemove/freddy/coverage)
3
+ [![Build Status](https://github.com/salemove/freddy/actions/workflows/ci.yml/badge.svg?branch=master)](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
- freddy.deliver(destination, message)
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
- * the parsed message (note that in the message all keys are symbolized)
79
- * the `MessageHandler` (described further down)
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
- * responding with a successful response
108
+ * responding with a successful response
109
+
88
110
  ```ruby
89
111
  msg_handler.success(response = nil)
90
112
  ```
91
113
 
92
- * responding with an error response
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
- * stop responding
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 [OpenTracing API|https://github.com/opentracing/opentracing-ruby]. You must set a global tracer which then freddy will use:
141
- ```ruby
142
- OpenTracing.global_tracing = MyTracerImplementation.new(...)
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
- See [opentracing-ruby](https://github.com/opentracing/opentracing-ruby) for more information.
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 = if RUBY_PLATFORM == 'java'
7
- 'freddy-jruby'
8
- else
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 = 'Private'
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
- if RUBY_PLATFORM == 'java'
27
- spec.add_dependency 'march_hare', '~> 2.12.0'
28
- spec.add_dependency 'symbolizer'
29
- else
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 < Shared::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
@@ -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
- if RUBY_PLATFORM == 'java'
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
- begin
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 do |delivery|
13
- yield(delivery)
14
- end
12
+ queue.subscribe(&block)
15
13
  end
16
14
  end
17
15
  end