shared_broker 1.1.1 → 1.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/CHANGELOG.md +18 -8
- data/README.md +1 -1
- data/lib/shared_broker/middleware_pipeline.rb +25 -0
- data/lib/shared_broker/middlewares/open_telemetry_propagation.rb +39 -0
- data/lib/shared_broker/version.rb +1 -1
- data/lib/shared_broker.rb +63 -51
- metadata +7 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d47439f3383e9d40d13664b67dc8b77318b64f628e6a1efa0f4684130ff2ff4b
|
|
4
|
+
data.tar.gz: 85d081f58ac1608a1629b29f14c634b370b963c65338eb7f9a32ace26bc90502
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 25151e9182b26d17334f04b121831703eee6c8b95981ac2b235085472501f06ec97c2a6b14cedc434dd3ee49963577b8eceedc175680525025d31e3246ac81dd
|
|
7
|
+
data.tar.gz: 07cb36e946dd24260fdd70d7cd995f4aeae8167b764d1df18e2026bc523481ec4d788308f720494472985a3b1a4adc7ae8751ded5abbd20b02c8c475c10a97c6
|
data/CHANGELOG.md
CHANGED
|
@@ -5,25 +5,35 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [1.
|
|
8
|
+
## [1.2.0] - 2026-06-07
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
|
-
-
|
|
12
|
-
-
|
|
11
|
+
- Pipeline of customizable Middlewares (Interceptors) for publishing and subscribing messages.
|
|
12
|
+
- Distributed Tracing using W3C Trace Context (`traceparent`/`tracestate`) context injection and extraction.
|
|
13
|
+
|
|
14
|
+
## [1.1.1] - 2026-06-06
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Restructured `README.md` to clearly separate minimum required configuration from optional/advanced setups.
|
|
18
|
+
|
|
19
|
+
## [1.1.0] - 2026-06-06
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- Scalable Adapters:
|
|
23
|
+
- Apache Kafka adapter (`SharedBroker::Adapters::Kafka`) with dynamic dependency loading.
|
|
24
|
+
- Redis Pub/Sub adapter (`SharedBroker::Adapters::Redis`) with list-based DLQ routing.
|
|
25
|
+
- Mock test configurations for Kafka and Redis to run adapter unit tests.
|
|
13
26
|
|
|
14
27
|
## [1.0.0] - 2026-06-06
|
|
15
28
|
|
|
16
29
|
### Added
|
|
17
|
-
-
|
|
30
|
+
- Fault Tolerance & Resilience features:
|
|
18
31
|
- Exponential backoff retry loop for message processing.
|
|
19
32
|
- Automatic Dead Letter Queue (DLQ) routing with rich metadata headers (`x_failed_at`, `x_exception_class`, `x_exception_message`, `x_original_routing_key`).
|
|
20
33
|
- Thread-safe `CircuitBreaker` wrapping all outbound publisher calls.
|
|
21
|
-
-
|
|
34
|
+
- Schema Validation and Security:
|
|
22
35
|
- Outbound/Inbound boundary validation using `dry-schema`.
|
|
23
36
|
- Transparent AES-256-GCM symmetric payload encryption by default, configurable with `SharedBroker.encryption_key`.
|
|
24
|
-
- Phase 3: Scalable Adapters:
|
|
25
|
-
- Apache Kafka adapter (`SharedBroker::Adapters::Kafka`) with dynamic dependency loading.
|
|
26
|
-
- Redis Pub/Sub adapter (`SharedBroker::Adapters::Redis`) with list-based DLQ routing.
|
|
27
37
|
- Comprehensive test coverage for all the above features using isolated fakes and Minitest.
|
|
28
38
|
|
|
29
39
|
## [0.1.0] - 2026-06-06
|
data/README.md
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SharedBroker
|
|
4
|
+
class MiddlewarePipeline
|
|
5
|
+
def initialize(middlewares)
|
|
6
|
+
@middlewares = Array(middlewares)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def execute(topic, message, metadata = {}, &block)
|
|
10
|
+
run_middleware(0, topic, message, metadata, &block)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def run_middleware(index, topic, message, metadata, &block)
|
|
16
|
+
if index >= @middlewares.size
|
|
17
|
+
yield
|
|
18
|
+
else
|
|
19
|
+
@middlewares[index].call(topic, message, metadata) do
|
|
20
|
+
run_middleware(index + 1, topic, message, metadata, &block)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "opentelemetry"
|
|
4
|
+
|
|
5
|
+
module SharedBroker
|
|
6
|
+
module Middlewares
|
|
7
|
+
class OpenTelemetryPropagation
|
|
8
|
+
def call(topic, message, metadata)
|
|
9
|
+
if metadata[:operation] == :publish
|
|
10
|
+
carrier = {}
|
|
11
|
+
::OpenTelemetry.propagation.inject(carrier)
|
|
12
|
+
carrier.each do |key, value|
|
|
13
|
+
message["_#{key}".to_sym] = value
|
|
14
|
+
end
|
|
15
|
+
yield
|
|
16
|
+
elsif metadata[:operation] == :subscribe
|
|
17
|
+
carrier = {}
|
|
18
|
+
message.each do |key, value|
|
|
19
|
+
if key.to_s.start_with?("_trace")
|
|
20
|
+
carrier[key.to_s.sub(/^_/, "")] = value
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
parent_context = ::OpenTelemetry.propagation.extract(carrier)
|
|
25
|
+
::OpenTelemetry::Context.with_current(parent_context) do
|
|
26
|
+
tracer = ::OpenTelemetry.tracer_provider.tracer("shared_broker")
|
|
27
|
+
tracer.in_span("#{topic} process", kind: :consumer) do |span|
|
|
28
|
+
span.set_attribute("messaging.system", "shared_broker")
|
|
29
|
+
span.set_attribute("messaging.destination", topic)
|
|
30
|
+
yield
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
else
|
|
34
|
+
yield
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/shared_broker.rb
CHANGED
|
@@ -1,51 +1,63 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "shared_broker/version"
|
|
4
|
-
require_relative "shared_broker/telemetry"
|
|
5
|
-
require_relative "shared_broker/circuit_breaker"
|
|
6
|
-
require_relative "shared_broker/validation"
|
|
7
|
-
require_relative "shared_broker/cipher"
|
|
8
|
-
require_relative "shared_broker/
|
|
9
|
-
require_relative "shared_broker/
|
|
10
|
-
require_relative "shared_broker/adapters/
|
|
11
|
-
require_relative "shared_broker/adapters/
|
|
12
|
-
require_relative "shared_broker/adapters/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
SharedBroker::
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "shared_broker/version"
|
|
4
|
+
require_relative "shared_broker/telemetry"
|
|
5
|
+
require_relative "shared_broker/circuit_breaker"
|
|
6
|
+
require_relative "shared_broker/validation"
|
|
7
|
+
require_relative "shared_broker/cipher"
|
|
8
|
+
require_relative "shared_broker/middleware_pipeline"
|
|
9
|
+
require_relative "shared_broker/middlewares/open_telemetry_propagation"
|
|
10
|
+
require_relative "shared_broker/adapters/base"
|
|
11
|
+
require_relative "shared_broker/adapters/in_memory"
|
|
12
|
+
require_relative "shared_broker/adapters/rabbit_mq"
|
|
13
|
+
require_relative "shared_broker/adapters/kafka"
|
|
14
|
+
require_relative "shared_broker/adapters/redis"
|
|
15
|
+
|
|
16
|
+
module SharedBroker
|
|
17
|
+
class << self
|
|
18
|
+
attr_accessor :encryption_key
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Default key for development/test if not set
|
|
22
|
+
@encryption_key = ENV.fetch("SHARED_BROKER_ENCRYPTION_KEY") { "a" * 32 }
|
|
23
|
+
|
|
24
|
+
class Client
|
|
25
|
+
attr_reader :circuit_breaker, :middleware_pipeline
|
|
26
|
+
|
|
27
|
+
def initialize(adapter:, circuit_breaker: nil, middlewares: nil)
|
|
28
|
+
unless adapter.respond_to?(:publish) && adapter.respond_to?(:subscribe)
|
|
29
|
+
raise ArgumentError, "Expected adapter to respond to :publish and :subscribe, got #{adapter.class} with value #{adapter.inspect}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
@adapter = adapter
|
|
33
|
+
@circuit_breaker = circuit_breaker || CircuitBreaker.new
|
|
34
|
+
|
|
35
|
+
resolved_middlewares = middlewares || [SharedBroker::Middlewares::OpenTelemetryPropagation.new]
|
|
36
|
+
@middleware_pipeline = MiddlewarePipeline.new(resolved_middlewares)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def publish(topic, message, correlation_id: nil)
|
|
40
|
+
metadata = { correlation_id: correlation_id, operation: :publish }
|
|
41
|
+
@middleware_pipeline.execute(topic, message, metadata) do
|
|
42
|
+
SharedBroker::Validation.validate!(topic, message)
|
|
43
|
+
encrypted_msg = SharedBroker::Cipher.encrypt(message, SharedBroker.encryption_key)
|
|
44
|
+
|
|
45
|
+
@circuit_breaker.run do
|
|
46
|
+
@adapter.publish(topic, encrypted_msg, correlation_id: correlation_id)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def subscribe(topic, queue_name, max_retries: 3, backoff_base: 2, &block)
|
|
52
|
+
@adapter.subscribe(topic, queue_name, max_retries: max_retries, backoff_base: backoff_base) do |raw_message|
|
|
53
|
+
decrypted_msg = SharedBroker::Cipher.decrypt(raw_message, SharedBroker.encryption_key)
|
|
54
|
+
SharedBroker::Validation.validate!(topic, decrypted_msg)
|
|
55
|
+
|
|
56
|
+
metadata = { correlation_id: decrypted_msg[:_correlation_id], operation: :subscribe, queue_name: queue_name }
|
|
57
|
+
@middleware_pipeline.execute(topic, decrypted_msg, metadata) do
|
|
58
|
+
block.call(decrypted_msg)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: shared_broker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- Wesley Lima
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bunny
|
|
@@ -125,7 +125,7 @@ dependencies:
|
|
|
125
125
|
description: Shared library for asynchronous messaging, distributed tracing, and customizable
|
|
126
126
|
adapters.
|
|
127
127
|
email:
|
|
128
|
-
-
|
|
128
|
+
- wesleyskap@gmail.com
|
|
129
129
|
executables: []
|
|
130
130
|
extensions: []
|
|
131
131
|
extra_rdoc_files: []
|
|
@@ -141,6 +141,8 @@ files:
|
|
|
141
141
|
- lib/shared_broker/adapters/redis.rb
|
|
142
142
|
- lib/shared_broker/cipher.rb
|
|
143
143
|
- lib/shared_broker/circuit_breaker.rb
|
|
144
|
+
- lib/shared_broker/middleware_pipeline.rb
|
|
145
|
+
- lib/shared_broker/middlewares/open_telemetry_propagation.rb
|
|
144
146
|
- lib/shared_broker/telemetry.rb
|
|
145
147
|
- lib/shared_broker/validation.rb
|
|
146
148
|
- lib/shared_broker/version.rb
|
|
@@ -150,7 +152,7 @@ licenses:
|
|
|
150
152
|
- MIT
|
|
151
153
|
metadata:
|
|
152
154
|
source_code_uri: https://github.com/wesleyskap/shared_broker
|
|
153
|
-
changelog_uri: https://github.com/wesleyskap/shared_broker/blob/
|
|
155
|
+
changelog_uri: https://github.com/wesleyskap/shared_broker/blob/master/CHANGELOG.md
|
|
154
156
|
post_install_message:
|
|
155
157
|
rdoc_options: []
|
|
156
158
|
require_paths:
|