freddy 1.6.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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