freddy 1.7.0 → 2.0.0

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