shared_broker 1.4.0 → 1.5.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 +8 -0
- data/README.md +14 -2
- data/lib/shared_broker/concurrency/limiter.rb +34 -0
- data/lib/shared_broker/concurrency/semaphore.rb +45 -0
- data/lib/shared_broker/version.rb +1 -1
- data/lib/shared_broker.rb +17 -7
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7fef9571ebd7987fe360d47b8a4374206808487afc3b641b19cb19c6dbfaf85f
|
|
4
|
+
data.tar.gz: 98fc3d5712273e6d426ac380e5ebd3ff4c9cd6319a1eb00b333ea25cc977cb0f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b6d52305cbfe8cd4e72d9e5bcbd84cc8bbda1c5c738a43e2727586e82f88bbe01d9e060d31ee28443c0b73172b4206ba33fd8640be394e6fba6b9b190f808a44
|
|
7
|
+
data.tar.gz: fdf993c33a31f8364aa613123159aebbeeae8ebfdd4f5548d6f1eb7210b318e0cc81f660e7ab28d4bc998868386c63086fbcc793d0cfe3ade14ffae82f8afd58
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,14 @@ 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.5.0] - 2026-06-10
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Concurrency Control & Adaptive Backpressure.
|
|
12
|
+
- `SharedBroker::Concurrency::Semaphore` pure-Ruby thread-safe semaphore implementation.
|
|
13
|
+
- `SharedBroker::Concurrency::Limiter` to manage dynamic backpressure checks and concurrency limits on message ingestion.
|
|
14
|
+
- Integrated concurrency parameters (`max_concurrency`, `backpressure_check`, `backpressure_backoff`) into `Client#subscribe`.
|
|
15
|
+
|
|
8
16
|
## [1.4.0] - 2026-06-10
|
|
9
17
|
|
|
10
18
|
### Added
|
data/README.md
CHANGED
|
@@ -177,14 +177,26 @@ event_data = {
|
|
|
177
177
|
SPOT_BROKER.publish("user.created", event_data)
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
### Subscribing to Events (Consumer with Retry
|
|
181
|
-
To start a persistent event subscriber daemon, register a queue/group name associated with the topic. You can customize the retries and
|
|
180
|
+
### Subscribing to Events (Consumer with Retry, DLQ, Concurrency & Backpressure)
|
|
181
|
+
To start a persistent event subscriber daemon, register a queue/group name associated with the topic. You can customize the retries, backoff rate, concurrency limits, and dynamic backpressure checks:
|
|
182
182
|
|
|
183
183
|
```ruby
|
|
184
|
+
# Basic subscriber
|
|
184
185
|
SPOT_BROKER.subscribe("user.created", "my_consumption_queue", max_retries: 3, backoff_base: 2) do |payload|
|
|
185
186
|
puts "Decrypted event successfully validated & consumed! ID: #{payload[:id]}"
|
|
186
187
|
# execute your business logic here...
|
|
187
188
|
end
|
|
189
|
+
|
|
190
|
+
# Advanced subscriber with Concurrency limits and Dynamic Backpressure
|
|
191
|
+
SPOT_BROKER.subscribe(
|
|
192
|
+
"user.created",
|
|
193
|
+
"my_consumption_queue",
|
|
194
|
+
max_concurrency: 5, # Process up to 5 events concurrently
|
|
195
|
+
backpressure_check: -> { db_overloaded? }, # Stop pulling new events if true
|
|
196
|
+
backpressure_backoff: 2.0 # Check health again after 2 seconds
|
|
197
|
+
) do |payload|
|
|
198
|
+
# business logic running within the concurrency wrapper
|
|
199
|
+
end
|
|
188
200
|
```
|
|
189
201
|
|
|
190
202
|
---
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "semaphore"
|
|
4
|
+
|
|
5
|
+
module SharedBroker
|
|
6
|
+
module Concurrency
|
|
7
|
+
class Limiter
|
|
8
|
+
def initialize(max_concurrency: nil, backpressure_check: nil, backpressure_backoff: 1.0)
|
|
9
|
+
@backpressure_check = backpressure_check
|
|
10
|
+
@backpressure_backoff = backpressure_backoff
|
|
11
|
+
@semaphore = max_concurrency ? Semaphore.new(max_concurrency) : nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def run
|
|
15
|
+
wait_while_overloaded
|
|
16
|
+
if @semaphore
|
|
17
|
+
@semaphore.synchronize { yield }
|
|
18
|
+
else
|
|
19
|
+
yield
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def wait_while_overloaded
|
|
26
|
+
return unless @backpressure_check
|
|
27
|
+
|
|
28
|
+
while @backpressure_check.call
|
|
29
|
+
sleep(@backpressure_backoff)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "thread"
|
|
4
|
+
|
|
5
|
+
module SharedBroker
|
|
6
|
+
module Concurrency
|
|
7
|
+
class Semaphore
|
|
8
|
+
def initialize(limit)
|
|
9
|
+
unless limit.is_a?(Integer) && limit > 0
|
|
10
|
+
raise ArgumentError, "Expected limit to be a positive Integer, got: #{limit.inspect} (class: #{limit.class})"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
@limit = limit
|
|
14
|
+
@count = 0
|
|
15
|
+
@mutex = Mutex.new
|
|
16
|
+
@cond = ConditionVariable.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def acquire
|
|
20
|
+
@mutex.synchronize do
|
|
21
|
+
while @count >= @limit
|
|
22
|
+
@cond.wait(@mutex)
|
|
23
|
+
end
|
|
24
|
+
@count += 1
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def release
|
|
29
|
+
@mutex.synchronize do
|
|
30
|
+
@count -= 1
|
|
31
|
+
@cond.signal
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def synchronize
|
|
36
|
+
acquire
|
|
37
|
+
begin
|
|
38
|
+
yield
|
|
39
|
+
ensure
|
|
40
|
+
release
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/shared_broker.rb
CHANGED
|
@@ -8,6 +8,8 @@ require_relative "shared_broker/schema_registry/providers/local"
|
|
|
8
8
|
require_relative "shared_broker/schema_registry/providers/http"
|
|
9
9
|
require_relative "shared_broker/validation"
|
|
10
10
|
require_relative "shared_broker/cipher"
|
|
11
|
+
require_relative "shared_broker/concurrency/semaphore"
|
|
12
|
+
require_relative "shared_broker/concurrency/limiter"
|
|
11
13
|
require_relative "shared_broker/middleware_pipeline"
|
|
12
14
|
require_relative "shared_broker/middlewares/open_telemetry_propagation"
|
|
13
15
|
require_relative "shared_broker/adapters/base"
|
|
@@ -46,14 +48,22 @@ module SharedBroker
|
|
|
46
48
|
end
|
|
47
49
|
end
|
|
48
50
|
|
|
49
|
-
def subscribe(topic, queue_name, max_retries: 3, backoff_base: 2, &block)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
def subscribe(topic, queue_name, max_retries: 3, backoff_base: 2, max_concurrency: nil, backpressure_check: nil, backpressure_backoff: 1.0, &block)
|
|
52
|
+
limiter = SharedBroker::Concurrency::Limiter.new(
|
|
53
|
+
max_concurrency: max_concurrency,
|
|
54
|
+
backpressure_check: backpressure_check,
|
|
55
|
+
backpressure_backoff: backpressure_backoff
|
|
56
|
+
)
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
resolve_adapter(topic).subscribe(topic, queue_name, max_retries: max_retries, backoff_base: backoff_base) do |raw_message|
|
|
59
|
+
limiter.run do
|
|
60
|
+
decrypted_msg = SharedBroker::Cipher.decrypt(raw_message, SharedBroker.encryption_key)
|
|
61
|
+
SharedBroker::Validation.validate!(topic, decrypted_msg)
|
|
62
|
+
|
|
63
|
+
metadata = { correlation_id: decrypted_msg[:_correlation_id], operation: :subscribe, queue_name: queue_name }
|
|
64
|
+
@middleware_pipeline.execute(topic, decrypted_msg, metadata) do
|
|
65
|
+
block.call(decrypted_msg)
|
|
66
|
+
end
|
|
57
67
|
end
|
|
58
68
|
end
|
|
59
69
|
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.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Wesley Lima
|
|
@@ -155,6 +155,8 @@ files:
|
|
|
155
155
|
- lib/shared_broker/adapters/redis.rb
|
|
156
156
|
- lib/shared_broker/cipher.rb
|
|
157
157
|
- lib/shared_broker/circuit_breaker.rb
|
|
158
|
+
- lib/shared_broker/concurrency/limiter.rb
|
|
159
|
+
- lib/shared_broker/concurrency/semaphore.rb
|
|
158
160
|
- lib/shared_broker/middleware_pipeline.rb
|
|
159
161
|
- lib/shared_broker/middlewares/open_telemetry_propagation.rb
|
|
160
162
|
- lib/shared_broker/schema_registry.rb
|