shared_broker 1.0.0 → 1.1.1
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 +35 -0
- data/README.md +40 -17
- data/lib/shared_broker/adapters/redis.rb +64 -0
- data/lib/shared_broker/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 545d29807ba6d68209d43f93f98b81b0e30532efe6d799d5df4f59650e8c44f8
|
|
4
|
+
data.tar.gz: 5eb9ac3cf999257d3c9f94db10140aee626ed42c1658dd727ca4e2b05f25eee9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 64d138f86ba1e88e86b2a65224df35946972843c928a73531b92b00e21bda3ab102a45b32e51db09a5c1f1d1ef7a6b9983e04978c5597408f74537ce01cbec1d
|
|
7
|
+
data.tar.gz: 7239a6c03ae9b78a8682e579a7d6becdd3c3edc782f8df587d13440d26f3f96e3695c96768890cb110372c3e6819f81bbd40ea90f628c21d03427743275dabb3
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.1.0] - Unreleased
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Phase 4: Pipeline of customizable Middlewares (Interceptors) for publishing and subscribing messages.
|
|
12
|
+
- Phase 4: Distributed Tracing using W3C Trace Context (`traceparent`/`tracestate`) injection and extraction.
|
|
13
|
+
|
|
14
|
+
## [1.0.0] - 2026-06-06
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- Phase 1: Fault Tolerance & Resilience features:
|
|
18
|
+
- Exponential backoff retry loop for message processing.
|
|
19
|
+
- Automatic Dead Letter Queue (DLQ) routing with rich metadata headers (`x_failed_at`, `x_exception_class`, `x_exception_message`, `x_original_routing_key`).
|
|
20
|
+
- Thread-safe `CircuitBreaker` wrapping all outbound publisher calls.
|
|
21
|
+
- Phase 2: Schema Validation and Security:
|
|
22
|
+
- Outbound/Inbound boundary validation using `dry-schema`.
|
|
23
|
+
- 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
|
+
- Comprehensive test coverage for all the above features using isolated fakes and Minitest.
|
|
28
|
+
|
|
29
|
+
## [0.1.0] - 2026-06-06
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
- Initial release with the pluggable `Client` messaging system.
|
|
33
|
+
- `InMemory` adapter for local testing.
|
|
34
|
+
- `RabbitMQ` adapter using the `bunny` gem.
|
|
35
|
+
- Basic OpenTelemetry instrumentation utility (`SharedBroker::Telemetry`).
|
data/README.md
CHANGED
|
@@ -44,36 +44,55 @@ bundle install
|
|
|
44
44
|
|
|
45
45
|
## Configuration
|
|
46
46
|
|
|
47
|
-
Create an initializer in your Rails application (`config/initializers/shared_broker.rb`)
|
|
47
|
+
Create an initializer in your Rails application (`config/initializers/shared_broker.rb`). Below is the breakdown of what is **required** versus what is **optional**.
|
|
48
|
+
|
|
49
|
+
### 1. Required Configuration (Minimum Setup)
|
|
50
|
+
|
|
51
|
+
You must configure the adapter depending on the environment, initialize the client, and configure the payload encryption key (required since AES-256-GCM is active by default):
|
|
48
52
|
|
|
49
53
|
```ruby
|
|
50
54
|
require "shared_broker"
|
|
51
55
|
|
|
52
|
-
#
|
|
53
|
-
|
|
54
|
-
required(:id).filled(:integer)
|
|
55
|
-
required(:email).filled(:string)
|
|
56
|
-
end
|
|
57
|
-
SharedBroker::Validation.register("user.created", user_created_schema)
|
|
58
|
-
|
|
59
|
-
# 2. Configure Payload Encryption Key (AES-256-GCM)
|
|
60
|
-
# Expects a 32-byte string. Default key is used in development if ENV is not set.
|
|
56
|
+
# A. Configure Payload Encryption Key (AES-256-GCM)
|
|
57
|
+
# Expects a 32-byte string. Use a secure production key in production.
|
|
61
58
|
SharedBroker.encryption_key = ENV.fetch("SHARED_BROKER_ENCRYPTION_KEY") { "a" * 32 }
|
|
62
59
|
|
|
63
|
-
#
|
|
60
|
+
# B. Configure the Adapter based on Environment
|
|
64
61
|
if Rails.env.test?
|
|
65
62
|
# In-memory adapter prevents external queue dependency during unit tests
|
|
66
63
|
BROKER_ADAPTER = SharedBroker::Adapters::InMemory.new
|
|
67
|
-
elsif Rails.env.production?
|
|
68
|
-
# High-throughput production setup using Kafka
|
|
69
|
-
BROKER_ADAPTER = SharedBroker::Adapters::Kafka.new(seed_brokers: ["kafka-1:9092", "kafka-2:9092"])
|
|
70
64
|
else
|
|
71
|
-
# Connects to RabbitMQ
|
|
65
|
+
# Connects to real RabbitMQ broker
|
|
72
66
|
amqp_url = ENV.fetch("RABBITMQ_URL") { "amqp://guest:guest@localhost:5672" }
|
|
73
67
|
BROKER_ADAPTER = SharedBroker::Adapters::RabbitMQ.new(amqp_url: amqp_url)
|
|
74
68
|
end
|
|
75
69
|
|
|
76
|
-
#
|
|
70
|
+
# C. Instantiate the Client by Injecting the Adapter
|
|
71
|
+
SPOT_BROKER = SharedBroker::Client.new(adapter: BROKER_ADAPTER)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### 2. Optional Configuration (Advanced Features)
|
|
77
|
+
|
|
78
|
+
These features can be configured optionally depending on your needs.
|
|
79
|
+
|
|
80
|
+
#### A. Event Payload Validation (dry-schema)
|
|
81
|
+
Register schemas to validate payload structure automatically on outbound (`publish`) and inbound (`subscribe`) boundaries:
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
user_created_schema = Dry::Schema.Params do
|
|
85
|
+
required(:id).filled(:integer)
|
|
86
|
+
required(:email).filled(:string)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
SharedBroker::Validation.register("user.created", user_created_schema)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### B. Custom Circuit Breaker
|
|
93
|
+
By default, the client instantiates a standard Circuit Breaker. You can provide a custom one to tune the failure threshold and recovery window:
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
77
96
|
custom_circuit_breaker = SharedBroker::CircuitBreaker.new(
|
|
78
97
|
failure_threshold: 5, # trip circuit after 5 failures
|
|
79
98
|
recovery_timeout: 30 # wait 30 seconds before attempting recovery
|
|
@@ -83,8 +102,12 @@ SPOT_BROKER = SharedBroker::Client.new(
|
|
|
83
102
|
adapter: BROKER_ADAPTER,
|
|
84
103
|
circuit_breaker: custom_circuit_breaker
|
|
85
104
|
)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### C. Initialize Distributed Tracing (OpenTelemetry)
|
|
108
|
+
Initialize the OpenTelemetry SDK with auto-instrumentation for the microservice:
|
|
86
109
|
|
|
87
|
-
|
|
110
|
+
```ruby
|
|
88
111
|
SharedBroker::Telemetry.configure(service_name: "my_microservice")
|
|
89
112
|
```
|
|
90
113
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
require "json"
|
|
5
|
+
require "time"
|
|
6
|
+
|
|
7
|
+
module SharedBroker
|
|
8
|
+
module Adapters
|
|
9
|
+
class Redis < Base
|
|
10
|
+
def initialize(redis_url:)
|
|
11
|
+
begin
|
|
12
|
+
require "redis"
|
|
13
|
+
rescue LoadError
|
|
14
|
+
raise unless defined?(::Redis)
|
|
15
|
+
end
|
|
16
|
+
@redis = ::Redis.new(url: redis_url)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def publish(topic, message, correlation_id: nil)
|
|
20
|
+
unless message.is_a?(Hash)
|
|
21
|
+
raise ArgumentError, "Expected message to be a Hash, got #{message.class} with value #{message.inspect}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
payload = message.merge(_correlation_id: correlation_id)
|
|
25
|
+
@redis.publish(topic, payload.to_json)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def subscribe(topic, queue_name, max_retries: 3, backoff_base: 2, &block)
|
|
29
|
+
Thread.new do
|
|
30
|
+
@redis.subscribe(topic) do |on|
|
|
31
|
+
on.message do |_channel, msg_json|
|
|
32
|
+
data = JSON.parse(msg_json, symbolize_names: true)
|
|
33
|
+
attempts = 0
|
|
34
|
+
begin
|
|
35
|
+
block.call(data)
|
|
36
|
+
rescue => e
|
|
37
|
+
attempts += 1
|
|
38
|
+
if attempts <= max_retries
|
|
39
|
+
sleep(backoff_base**attempts)
|
|
40
|
+
retry
|
|
41
|
+
else
|
|
42
|
+
publish_to_dlq(topic, queue_name, msg_json, e)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def publish_to_dlq(topic, queue_name, payload_json, exception)
|
|
53
|
+
dlq_key = "dlq:#{topic}:#{queue_name}"
|
|
54
|
+
dlq_payload = {
|
|
55
|
+
payload: JSON.parse(payload_json, symbolize_names: true),
|
|
56
|
+
x_failed_at: Time.now.utc.iso8601,
|
|
57
|
+
x_exception_class: exception.class.name,
|
|
58
|
+
x_exception_message: exception.message
|
|
59
|
+
}
|
|
60
|
+
@redis.rpush(dlq_key, dlq_payload.to_json)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: shared_broker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gemini Antigravity
|
|
@@ -130,6 +130,7 @@ executables: []
|
|
|
130
130
|
extensions: []
|
|
131
131
|
extra_rdoc_files: []
|
|
132
132
|
files:
|
|
133
|
+
- CHANGELOG.md
|
|
133
134
|
- README.md
|
|
134
135
|
- Rakefile
|
|
135
136
|
- lib/shared_broker.rb
|
|
@@ -137,18 +138,19 @@ files:
|
|
|
137
138
|
- lib/shared_broker/adapters/in_memory.rb
|
|
138
139
|
- lib/shared_broker/adapters/kafka.rb
|
|
139
140
|
- lib/shared_broker/adapters/rabbit_mq.rb
|
|
141
|
+
- lib/shared_broker/adapters/redis.rb
|
|
140
142
|
- lib/shared_broker/cipher.rb
|
|
141
143
|
- lib/shared_broker/circuit_breaker.rb
|
|
142
144
|
- lib/shared_broker/telemetry.rb
|
|
143
145
|
- lib/shared_broker/validation.rb
|
|
144
146
|
- lib/shared_broker/version.rb
|
|
145
147
|
- sig/shared_broker.rbs
|
|
146
|
-
homepage: https://github.com/
|
|
148
|
+
homepage: https://github.com/wesleyskap/shared_broker
|
|
147
149
|
licenses:
|
|
148
150
|
- MIT
|
|
149
151
|
metadata:
|
|
150
|
-
source_code_uri: https://github.com/
|
|
151
|
-
changelog_uri: https://github.com/
|
|
152
|
+
source_code_uri: https://github.com/wesleyskap/shared_broker
|
|
153
|
+
changelog_uri: https://github.com/wesleyskap/shared_broker/blob/main/CHANGELOG.md
|
|
152
154
|
post_install_message:
|
|
153
155
|
rdoc_options: []
|
|
154
156
|
require_paths:
|