Skip to content

Commit 2acde0c

Browse files
Remove thread local registry.
1 parent f2d6c48 commit 2acde0c

File tree

3 files changed

+30
-69
lines changed

3 files changed

+30
-69
lines changed

lib/async/utilization.rb

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,42 +15,9 @@ module Async
1515
#
1616
# This module provides a convenient interface for tracking utilization metrics
1717
# that can be synchronized to shared memory for inter-process communication.
18-
# Each thread gets its own instance of the underlying {Registry}, providing
19-
# thread-local behavior.
18+
# Registries should be explicitly created and passed to components that need them.
2019
#
2120
# See the {file:guides/getting-started/readme.md Getting Started} guide for usage examples.
2221
module Utilization
23-
# Set the observer for utilization metrics.
24-
#
25-
# When an observer is set, it is notified of all current metric values
26-
# so it can sync its state. The observer must implement `set(field, value)`.
27-
#
28-
# Delegates to the thread-local {Registry} instance.
29-
#
30-
# @parameter observer [#set] The observer to set.
31-
def self.observer=(observer)
32-
Registry.instance.observer = observer
33-
end
34-
35-
# Get a cached metric reference for a field.
36-
#
37-
# Returns a {Metric} instance that caches all details needed for fast writes
38-
# to shared memory, avoiding hash lookups on the fast path.
39-
#
40-
# This is the recommended way to access metrics for optimal performance.
41-
#
42-
# Delegates to the thread-local {Registry} instance.
43-
#
44-
# @parameter field [Symbol] The field name to get a metric for.
45-
# @returns [Metric] A metric instance for the given field.
46-
# @example Get a metric and increment it:
47-
# current_requests = Async::Utilization.metric(:current_requests)
48-
# current_requests.increment
49-
# current_requests.increment do
50-
# # Handle request - auto-decrements when block completes
51-
# end
52-
def self.metric(field)
53-
Registry.instance.metric(field)
54-
end
5522
end
5623
end

lib/async/utilization/registry.rb

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@
33
# Released under the MIT License.
44
# Copyright, 2026, by Samuel Williams.
55

6-
require "thread/local"
7-
86
module Async
97
module Utilization
108
# Registry for emitting utilization metrics.
119
#
1210
# The registry tracks values directly and notifies a registered observer
1311
# when values change. The observer (like Observer) can write to its backend.
1412
#
15-
# Each thread gets its own instance of the registry, providing
16-
# thread-local behavior through the thread-local gem.
13+
# Registries should be explicitly created and passed to components that need them.
14+
# In service contexts, registries are typically created via the evaluator and
15+
# shared across components within the same service instance.
1716
#
1817
# When an observer is added, it is immediately notified of all current values
1918
# so it can sync its state. When values change, the observer is notified.
@@ -36,7 +35,6 @@ module Utilization
3635
# observer = Async::Utilization::Observer.open(schema, "/path/to/shm", 4096, 0)
3736
# registry.observer = observer
3837
class Registry
39-
extend Thread::Local
4038

4139
# Initialize a new registry.
4240
def initialize

test/async/utilization/metric.rb

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,24 @@
2929
Async::Utilization::Observer.open(schema, shm_path, segment_size, offset)
3030
end
3131

32+
let(:registry) {Async::Utilization::Registry.new}
33+
3234
before do
3335
File.open(shm_path, "w+b") do |file|
3436
file.truncate(file_size)
3537
end
36-
37-
# Reset the registry to ensure clean state between tests
38-
registry = Async::Utilization::Registry.instance
39-
registry.instance_variable_set(:@values, Hash.new(0))
40-
registry.instance_variable_set(:@metrics, {})
41-
registry.instance_variable_set(:@observer, nil)
4238
end
4339

4440
it "can create a metric from a field name" do
45-
metric = Async::Utilization.metric(:total_requests)
41+
metric = registry.metric(:total_requests)
4642

4743
expect(metric).to be_a(Async::Utilization::Metric)
4844
expect(metric.name).to be == :total_requests
4945
end
5046

5147
it "can increment a metric" do
52-
Async::Utilization.observer = observer
53-
metric = Async::Utilization.metric(:total_requests)
48+
registry.observer = observer
49+
metric = registry.metric(:total_requests)
5450

5551
value = metric.increment
5652
expect(value).to be == 1
@@ -62,8 +58,8 @@
6258
end
6359

6460
it "can decrement a metric" do
65-
Async::Utilization.observer = observer
66-
metric = Async::Utilization.metric(:total_requests)
61+
registry.observer = observer
62+
metric = registry.metric(:total_requests)
6763

6864
metric.increment
6965
metric.increment
@@ -74,8 +70,8 @@
7470
end
7571

7672
it "can set a metric value" do
77-
Async::Utilization.observer = observer
78-
metric = Async::Utilization.metric(:total_requests)
73+
registry.observer = observer
74+
metric = registry.metric(:total_requests)
7975

8076
metric.set(42)
8177
expect(metric.value).to be == 42
@@ -85,8 +81,8 @@
8581
end
8682

8783
it "can increment with auto-decrement block" do
88-
Async::Utilization.observer = observer
89-
metric = Async::Utilization.metric(:active_requests)
84+
registry.observer = observer
85+
metric = registry.metric(:active_requests)
9086

9187
metric.increment do
9288
expect(metric.value).to be == 1
@@ -96,8 +92,8 @@
9692
end
9793

9894
it "decrements even if block raises an error" do
99-
Async::Utilization.observer = observer
100-
metric = Async::Utilization.metric(:active_requests)
95+
registry.observer = observer
96+
metric = registry.metric(:active_requests)
10197

10298
begin
10399
metric.increment do
@@ -111,8 +107,8 @@
111107
end
112108

113109
it "writes directly to shared memory when observer is set" do
114-
Async::Utilization.observer = observer
115-
metric = Async::Utilization.metric(:total_requests)
110+
registry.observer = observer
111+
metric = registry.metric(:total_requests)
116112

117113
metric.set(42)
118114

@@ -122,8 +118,8 @@
122118
end
123119

124120
it "invalidates cache when observer changes" do
125-
Async::Utilization.observer = observer
126-
metric = Async::Utilization.metric(:total_requests)
121+
registry.observer = observer
122+
metric = registry.metric(:total_requests)
127123

128124
# Set a value - cache should be built
129125
metric.set(10)
@@ -139,7 +135,7 @@
139135
new_observer = Async::Utilization::Observer.open(new_schema, new_shm_path, segment_size, 0)
140136

141137
# Change observer - cache should be invalidated
142-
Async::Utilization.observer = new_observer
138+
registry.observer = new_observer
143139

144140
# Set a new value - cache should be rebuilt
145141
metric.set(20)
@@ -151,7 +147,7 @@
151147
end
152148

153149
it "works without an observer" do
154-
metric = Async::Utilization.metric(:total_requests)
150+
metric = registry.metric(:total_requests)
155151

156152
# Should work fine without observer (uses fallback path)
157153
metric.increment
@@ -161,21 +157,21 @@
161157
expect(metric.value).to be == 5
162158

163159
# Set observer and verify it works with fast path
164-
Async::Utilization.observer = observer
160+
registry.observer = observer
165161
metric.set(10)
166162
expect(metric.value).to be == 10
167163
end
168164

169165
it "returns the same metric instance for the same field" do
170-
metric1 = Async::Utilization.metric(:total_requests)
171-
metric2 = Async::Utilization.metric(:total_requests)
166+
metric1 = registry.metric(:total_requests)
167+
metric2 = registry.metric(:total_requests)
172168

173169
expect(metric1).to be == metric2
174170
end
175171

176172
it "falls back to observer.set when write_direct fails" do
177-
Async::Utilization.observer = observer
178-
metric = Async::Utilization.metric(:total_requests)
173+
registry.observer = observer
174+
metric = registry.metric(:total_requests)
179175

180176
# Force cache to be invalid by invalidating it
181177
metric.invalidate
@@ -190,8 +186,8 @@
190186
end
191187

192188
it "handles write errors gracefully" do
193-
Async::Utilization.observer = observer
194-
metric = Async::Utilization.metric(:total_requests)
189+
registry.observer = observer
190+
metric = registry.metric(:total_requests)
195191

196192
# Set a value first to build the cache
197193
metric.set(10)

0 commit comments

Comments
 (0)