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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b161a64893a9f15f9bb4568c1b281c2851904bc9e8730e8992d5f6d0847a4de4
4
- data.tar.gz: 6a771b8df2dc371516b2d7f97d6e157ff493141034106c40236f952c6aef0f2e
3
+ metadata.gz: 7fef9571ebd7987fe360d47b8a4374206808487afc3b641b19cb19c6dbfaf85f
4
+ data.tar.gz: 98fc3d5712273e6d426ac380e5ebd3ff4c9cd6319a1eb00b333ea25cc977cb0f
5
5
  SHA512:
6
- metadata.gz: '06494d11f1575ac5e13353acad3e9896f9ff7e5b7f64b164cecaa39b492aadeb170590e2ec9c9628c80691d08fc521e07e384fa43d2fe4e7874424704e39aedb'
7
- data.tar.gz: 6781b513d75bd232c5c75738a6078aad08d096133e410335ec707ac203548b653af222bbb37ee7594fff40044e8122f8e362b12f68927939a7a19655f021ca16
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 and DLQ)
181
- To start a persistent event subscriber daemon, register a queue/group name associated with the topic. You can customize the retries and backoff rate:
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SharedBroker
4
- VERSION = "1.4.0"
4
+ VERSION = "1.5.0"
5
5
  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
- resolve_adapter(topic).subscribe(topic, queue_name, max_retries: max_retries, backoff_base: backoff_base) do |raw_message|
51
- decrypted_msg = SharedBroker::Cipher.decrypt(raw_message, SharedBroker.encryption_key)
52
- SharedBroker::Validation.validate!(topic, decrypted_msg)
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
- metadata = { correlation_id: decrypted_msg[:_correlation_id], operation: :subscribe, queue_name: queue_name }
55
- @middleware_pipeline.execute(topic, decrypted_msg, metadata) do
56
- block.call(decrypted_msg)
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.0
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