freddy 1.7.0 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b7b2906e383a27fec45165c162d2a0a7a3a299dfdf390c599cf42288d75e5f3e
4
- data.tar.gz: 882a6d64838f723c43c58189cd0b9786df758bdd357ea23dfcb2954c454fb92f
3
+ metadata.gz: 7ae99c2d347a67110923b71ffac1af46c706d177b39b82c3adaae4db3f686a1d
4
+ data.tar.gz: 557210126d3c4cdff8f0946ee5b6882e3334126c3cb0ae900df823f6e762fdd9
5
5
  SHA512:
6
- metadata.gz: b0d5031e6308383f5905f40ecc817945be9dd6df1f0abc6be662867d8d5b39b6c57ed0615d56d26d46ddcfe9dc05b4bc2d7a86b8f46d89d5ed118963b0c36063
7
- data.tar.gz: 816406b89fb3fbac83fffd15b5d283755096675dc4f9095b041c585d950a47a11c46bb1ef1545747b08775c705531b7c383327d06bdba2175a96cb7bf6f3732b
6
+ metadata.gz: a2ee88b1ec7e51523ae6b3851f07b398b9093d90b193712bce172a09764d2a683d0b5209ced2a4a524248d8ffab36074b8a0b65c662ef9844f319424ccb32e93
7
+ data.tar.gz: ea65f5f23e18c768098c1eec7edc299a146f0fc830a0a57b5e9d1f725b5fe6f0b442b017ecd08b80f6242424a6a0958b57c8514cdf015bca07e4d316e88edc56
@@ -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.7']
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.7
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
 
@@ -147,14 +145,11 @@ responder_handler.shutdown
147
145
 
148
146
  ## Request Tracing
149
147
 
150
- Freddy supports [OpenTracing API|https://github.com/opentracing/opentracing-ruby]. You must set a global tracer which then freddy will use:
151
- ```ruby
152
- OpenTracing.global_tracing = MyTracerImplementation.new(...)
153
- ```
154
-
155
- 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.
148
+ Freddy supports [OpenTelemetry API|https://github.com/open-telemetry/opentelemetry-ruby].
149
+ The trace information is automatically passed through `deliver`,
150
+ `deliver_with_response`, `respond_to` and `tap_into` calls.
156
151
 
157
- See [opentracing-ruby](https://github.com/opentracing/opentracing-ruby) for more information.
152
+ This is not compatible with `opentelemetry-instrumentation-bunny` library.
158
153
 
159
154
  ## Notes about concurrency
160
155
 
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.7.0'
6
+ spec.name = 'freddy'
7
+ spec.version = Freddy::VERSION
12
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.7'
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,9 @@ 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'
36
29
  end
data/lib/freddy.rb CHANGED
@@ -3,9 +3,11 @@
3
3
  require 'json'
4
4
  require 'thread/pool'
5
5
  require 'securerandom'
6
- require 'opentracing'
6
+ require 'opentelemetry'
7
+ require 'opentelemetry/semantic_conventions'
8
+ require_relative './freddy/version'
7
9
 
8
- Dir[File.dirname(__FILE__) + '/freddy/*.rb'].each(&method(:require))
10
+ Dir["#{File.dirname(__FILE__)}/freddy/*.rb"].sort.each(&method(:require))
9
11
 
10
12
  class Freddy
11
13
  FREDDY_TOPIC_EXCHANGE_NAME = 'freddy-topic'
@@ -26,22 +28,15 @@ class Freddy
26
28
  # @return [Freddy]
27
29
  #
28
30
  # @example
29
- # Freddy.build(Logger.new(STDOUT), user: 'thumper', pass: 'howdy')
30
- def self.build(logger = Logger.new(STDOUT), max_concurrency: DEFAULT_MAX_CONCURRENCY, **config)
31
- OpenTracing.global_tracer ||= OpenTracing::Tracer.new
32
-
31
+ # Freddy.build(Logger.new($stdout), user: 'thumper', pass: 'howdy')
32
+ def self.build(logger = Logger.new($stdout), max_concurrency: DEFAULT_MAX_CONCURRENCY, **config)
33
33
  connection = Adapters.determine.connect(config)
34
34
  new(connection, logger, max_concurrency)
35
35
  end
36
36
 
37
- # @deprecated Use {OpenTracing.active_span} instead
38
- def self.trace
39
- OpenTracing.active_span
40
- end
41
-
42
- # @deprecated Use OpenTracing ScopeManager instead
43
- def self.trace=(trace)
44
- OpenTracing.scope_manager.activate(trace) if OpenTracing.active_span != trace
37
+ # @private
38
+ def self.tracer
39
+ @tracer ||= OpenTelemetry.tracer_provider.tracer('freddy', Freddy::VERSION)
45
40
  end
46
41
 
47
42
  def initialize(connection, logger, max_concurrency)
@@ -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
@@ -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
70
  parsed_payload = Payload.parse(payload)
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,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Dir[File.dirname(__FILE__) + '/consumers/*.rb'].each(&method(:require))
3
+ Dir["#{File.dirname(__FILE__)}/consumers/*.rb"].sort.each(&method(:require))
@@ -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
@@ -47,33 +47,21 @@ class Freddy
47
47
 
48
48
  def process_message(_queue, delivery)
49
49
  @consume_thread_pool.process do
50
- begin
51
- scope = delivery.build_trace("freddy:observe:#{@pattern}",
52
- tags: {
53
- 'message_bus.destination' => @pattern,
54
- 'message_bus.correlation_id' => delivery.correlation_id,
55
- 'component' => 'freddy',
56
- 'span.kind' => 'consumer' # Message Bus
57
- },
58
- force_follows_from: true)
59
-
50
+ delivery.in_span(force_follows_from: true) do
60
51
  yield delivery.payload, delivery.routing_key
61
-
62
52
  @channel.acknowledge(delivery.tag)
63
- rescue StandardError
64
- case on_exception
65
- when :reject
66
- @channel.reject(delivery.tag)
67
- when :requeue
68
- @channel.reject(delivery.tag, true)
69
- else
70
- @channel.acknowledge(delivery.tag)
71
- end
72
-
73
- raise
74
- ensure
75
- scope.close
76
53
  end
54
+ rescue StandardError
55
+ case on_exception
56
+ when :reject
57
+ @channel.reject(delivery.tag)
58
+ when :requeue
59
+ @channel.reject(delivery.tag, true)
60
+ else
61
+ @channel.acknowledge(delivery.tag)
62
+ end
63
+
64
+ raise
77
65
  end
78
66
  end
79
67
 
@@ -4,11 +4,12 @@ class Freddy
4
4
  class Delivery
5
5
  attr_reader :routing_key, :payload, :tag
6
6
 
7
- def initialize(payload, metadata, routing_key, tag)
7
+ def initialize(payload, metadata, routing_key, tag, exchange)
8
8
  @payload = payload
9
9
  @metadata = metadata
10
10
  @routing_key = routing_key
11
11
  @tag = tag
12
+ @exchange = exchange
12
13
  end
13
14
 
14
15
  def correlation_id
@@ -23,20 +24,52 @@ class Freddy
23
24
  @metadata.reply_to
24
25
  end
25
26
 
26
- def build_trace(operation_name, tags: {}, force_follows_from: false)
27
- carrier = TraceCarrier.new(@metadata)
28
- parent = OpenTracing.global_tracer.extract(OpenTracing::FORMAT_TEXT_MAP, carrier)
29
-
30
- references =
31
- if !parent
32
- []
33
- elsif force_follows_from
34
- [OpenTracing::Reference.follows_from(parent)]
35
- else
36
- [OpenTracing::Reference.child_of(parent)]
27
+ def in_span(force_follows_from: false, &block)
28
+ name = "#{@exchange}.#{@routing_key} receive"
29
+ kind = OpenTelemetry::Trace::SpanKind::CONSUMER
30
+ producer_context = OpenTelemetry.propagation.extract(@metadata[:headers] || {})
31
+
32
+ if force_follows_from
33
+ producer_span_context = OpenTelemetry::Trace.current_span(producer_context).context
34
+
35
+ links = []
36
+ links << OpenTelemetry::Trace::Link.new(producer_span_context) if producer_span_context.valid?
37
+
38
+ # In general we should start a new trace here and just link two traces
39
+ # together. But Zipkin (which we currently use) doesn't support links.
40
+ # So even though the root trace could finish before anything here
41
+ # starts executing, we'll continue with the root trace here as well.
42
+ OpenTelemetry::Context.with_current(producer_context) do
43
+ Freddy.tracer.in_span(name, attributes: span_attributes, links: links, kind: kind, &block)
37
44
  end
45
+ else
46
+ OpenTelemetry::Context.with_current(producer_context) do
47
+ Freddy.tracer.in_span(name, attributes: span_attributes, kind: kind, &block)
48
+ end
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def span_attributes
55
+ destination_kind = @exchange == '' ? 'queue' : 'topic'
56
+
57
+ attributes = {
58
+ 'payload.type' => (@payload[:type] || 'unknown').to_s,
59
+ OpenTelemetry::SemanticConventions::Trace::MESSAGING_SYSTEM => 'rabbitmq',
60
+ OpenTelemetry::SemanticConventions::Trace::MESSAGING_DESTINATION => @exchange,
61
+ OpenTelemetry::SemanticConventions::Trace::MESSAGING_DESTINATION_KIND => destination_kind,
62
+ OpenTelemetry::SemanticConventions::Trace::MESSAGING_RABBITMQ_ROUTING_KEY => @routing_key,
63
+ OpenTelemetry::SemanticConventions::Trace::MESSAGING_OPERATION => 'receive'
64
+ }
65
+
66
+ # There's no correlation_id when a message was sent using
67
+ # `Freddy#deliver`.
68
+ if correlation_id
69
+ attributes[OpenTelemetry::SemanticConventions::Trace::MESSAGING_CONVERSATION_ID] = correlation_id
70
+ end
38
71
 
39
- OpenTracing.start_active_span(operation_name, references: references, tags: tags)
72
+ attributes
40
73
  end
41
74
  end
42
75
  end