local_bus 0.1.2 → 0.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/README.md +21 -20
- data/lib/local_bus/bus.rb +12 -12
- data/lib/local_bus/station.rb +5 -5
- data/lib/local_bus/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f435ed1460835bdd4b50311c366c158f4dda0381038368cd325a13c8ceace3b9
|
4
|
+
data.tar.gz: 937b58aa97ed2e9ca2f65eb02b6c401f9e93c4d590aff5966816dd6dd47be8a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74828920b50a51ae3fc00583dee61657d88cadd62482172fc34c1e54e935a652306716242c9152d6a5f35e9660f6d52930c6840966dc281f158c391666588cf7
|
7
|
+
data.tar.gz: d7c86027a16144325f3ea4cd3e65f41ea55a56ac6b75e309a75a5397cd7042372002783948f64b6e76d3cdbb0200a1cd0b62be3ec8c632b3639c5c33b0a42a76
|
data/README.md
CHANGED
@@ -30,22 +30,23 @@ LocalBus is a lightweight pub/sub system for Ruby that helps organize and simpli
|
|
30
30
|
|
31
31
|
## Table of Contents
|
32
32
|
|
33
|
-
- [Why LocalBus?](#why-localbus)
|
34
|
-
- [Installation](#installation)
|
35
|
-
- [Quick Start](#quick-start)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
- [Advanced Usage & Considerations](#advanced-usage--considerations)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
- [
|
33
|
+
- [Why LocalBus?](#why-localbus)
|
34
|
+
- [Installation](#installation)
|
35
|
+
- [Quick Start](#quick-start)
|
36
|
+
- [Interfaces](#interfaces)
|
37
|
+
- [Bus (immediate processing)](#bus-immediate-processing)
|
38
|
+
- [Station (background processing)](#station-background-processing)
|
39
|
+
- [Advanced Usage & Considerations](#advanced-usage--considerations)
|
40
|
+
- [Concurrency Controls](#concurrency-controls)
|
41
|
+
- [Bus Interface (Async)](#bus-interface-async)
|
42
|
+
- [Station Interface (Thread Pool)](#station-interface-thread-pool)
|
43
|
+
- [Error Handling & Recovery](#error-handling--recovery)
|
44
|
+
- [Memory Considerations](#memory-considerations)
|
45
|
+
- [Blocking Operations](#blocking-operations)
|
46
|
+
- [Shutdown & Cleanup](#shutdown--cleanup)
|
47
|
+
- [Limitations](#limitations)
|
48
|
+
- [See Also](#see-also)
|
49
|
+
- [Sponsors](#sponsors)
|
49
50
|
|
50
51
|
<!-- Tocer[finish]: Auto-generated, don't remove. -->
|
51
52
|
|
@@ -184,7 +185,7 @@ The Bus interface uses Async's Semaphore to limit resource consumption:
|
|
184
185
|
|
185
186
|
```ruby
|
186
187
|
# Configure concurrency limits for the Bus
|
187
|
-
bus = LocalBus::Bus.new(
|
188
|
+
bus = LocalBus::Bus.new(max_concurrency: 10)
|
188
189
|
|
189
190
|
# The semaphore ensures only N concurrent operations run at once
|
190
191
|
bus.subscribe "resource.intensive" do |message|
|
@@ -193,7 +194,7 @@ bus.subscribe "resource.intensive" do |message|
|
|
193
194
|
end
|
194
195
|
```
|
195
196
|
|
196
|
-
When the concurrency limit is reached, new publish operations will wait until a slot becomes available. This prevents memory bloat but means you should be mindful of timeouts in your subscribers.
|
197
|
+
When the max concurrency limit is reached, new publish operations will wait until a slot becomes available. This prevents memory bloat but means you should be mindful of timeouts in your subscribers.
|
197
198
|
|
198
199
|
#### Station Interface (Thread Pool)
|
199
200
|
|
@@ -203,7 +204,7 @@ The Station interface uses Concurrent Ruby's fixed thread pool with a fallback p
|
|
203
204
|
# Configure the thread pool size for the Station
|
204
205
|
station = LocalBus::Station.new(
|
205
206
|
max_queue: 5_000, # Maximum number of queued items
|
206
|
-
|
207
|
+
max_threads: 10, # Maximum pool size
|
207
208
|
fallback_policy: :caller_runs # Runs on calling thread
|
208
209
|
)
|
209
210
|
```
|
@@ -275,7 +276,7 @@ For example, idempotency _(i.e. messages that can be re-published without uninte
|
|
275
276
|
|
276
277
|
- The Bus interface is single-threaded - long-running subscribers can impact latency
|
277
278
|
- The Station interface may drop messages if configured with `:discard` fallback policy
|
278
|
-
- No persistence - pending messages
|
279
|
+
- No persistence - pending messages may be lost on process restart
|
279
280
|
- No distributed support - communication limited to single process
|
280
281
|
- Large payloads can impact memory usage, especially under high load
|
281
282
|
- No built-in retry mechanism for failed subscribers
|
data/lib/local_bus/bus.rb
CHANGED
@@ -8,27 +8,27 @@ class LocalBus
|
|
8
8
|
include MonitorMixin
|
9
9
|
|
10
10
|
# Constructor
|
11
|
-
# @note Creates a new Bus instance with specified concurrency
|
12
|
-
# @rbs
|
13
|
-
def initialize(
|
11
|
+
# @note Creates a new Bus instance with specified max concurrency (i.e. number of tasks that can run in parallel)
|
12
|
+
# @rbs max_concurrency: Integer -- maximum number of concurrent tasks (default: Concurrent.processor_count)
|
13
|
+
def initialize(max_concurrency: Concurrent.processor_count)
|
14
14
|
super()
|
15
|
-
@
|
15
|
+
@max_concurrency = max_concurrency.to_i
|
16
16
|
@subscriptions = Concurrent::Hash.new do |hash, key|
|
17
17
|
hash[key] = Concurrent::Set.new
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
# Maximum number of concurrent tasks that can run in "parallel"
|
22
|
-
# @rbs return: Integer
|
23
|
-
def
|
24
|
-
synchronize { @
|
22
|
+
# @rbs return: Integer
|
23
|
+
def max_concurrency
|
24
|
+
synchronize { @max_concurrency }
|
25
25
|
end
|
26
26
|
|
27
|
-
# Sets the concurrency
|
28
|
-
# @rbs
|
27
|
+
# Sets the max concurrency
|
28
|
+
# @rbs value: Integer -- max number of concurrent tasks that can run in "parallel"
|
29
29
|
# @rbs return: Integer -- new concurrency value
|
30
|
-
def
|
31
|
-
synchronize { @
|
30
|
+
def max_concurrency=(value)
|
31
|
+
synchronize { @max_concurrency = value.to_i }
|
32
32
|
end
|
33
33
|
|
34
34
|
# Registered topics that have subscribers
|
@@ -112,7 +112,7 @@ class LocalBus
|
|
112
112
|
if subscribers.any?
|
113
113
|
Sync do |task|
|
114
114
|
task.with_timeout timeout.to_f do
|
115
|
-
semaphore = Async::Semaphore.new(
|
115
|
+
semaphore = Async::Semaphore.new(max_concurrency, parent: barrier)
|
116
116
|
|
117
117
|
subscribers.each do |subscriber|
|
118
118
|
semaphore.async do
|
data/lib/local_bus/station.rb
CHANGED
@@ -33,21 +33,21 @@ class LocalBus
|
|
33
33
|
|
34
34
|
# Constructor
|
35
35
|
# @rbs bus: Bus -- local message bus (default: Bus.new)
|
36
|
-
# @rbs
|
36
|
+
# @rbs max_threads: Integer -- number of max_threads (default: Concurrent.processor_count)
|
37
37
|
# @rbs default_timeout: Float -- seconds to wait for a future to complete
|
38
38
|
# @rbs shutdown_timeout: Float -- seconds to wait for all futures to complete on process exit
|
39
39
|
# @rbs options: Hash[Symbol, untyped] -- Concurrent::FixedThreadPool options
|
40
40
|
# @rbs return: void
|
41
41
|
def initialize(
|
42
42
|
bus: Bus.new,
|
43
|
-
|
43
|
+
max_threads: Concurrent.processor_count,
|
44
44
|
default_timeout: 0,
|
45
45
|
shutdown_timeout: 8,
|
46
46
|
**options
|
47
47
|
)
|
48
48
|
super()
|
49
49
|
@bus = bus
|
50
|
-
@
|
50
|
+
@max_threads = [2, max_threads].max.to_i
|
51
51
|
@default_timeout = default_timeout.to_f
|
52
52
|
@shutdown_timeout = shutdown_timeout.to_f
|
53
53
|
@shutdown = Concurrent::AtomicBoolean.new(false)
|
@@ -60,7 +60,7 @@ class LocalBus
|
|
60
60
|
|
61
61
|
# Number of threads used to process messages
|
62
62
|
# @rbs return: Integer
|
63
|
-
attr_reader :
|
63
|
+
attr_reader :max_threads
|
64
64
|
|
65
65
|
# Default timeout for message processing (in seconds)
|
66
66
|
# @rbs return: Float
|
@@ -78,7 +78,7 @@ class LocalBus
|
|
78
78
|
return if running?
|
79
79
|
|
80
80
|
start_shutdown_handler
|
81
|
-
@pool = Concurrent::FixedThreadPool.new(
|
81
|
+
@pool = Concurrent::FixedThreadPool.new(max_threads, THREAD_POOL_OPTIONS.merge(options))
|
82
82
|
enable_safe_shutdown on: ["HUP", "INT", "QUIT", "TERM"]
|
83
83
|
end
|
84
84
|
end
|
data/lib/local_bus/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: local_bus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nate Hopkins (hopsoft)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-11-
|
11
|
+
date: 2024-11-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async
|