yabeda-rack-queue 0.1.0 → 0.2.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 +22 -0
- data/Gemfile.lock +2 -2
- data/README.md +5 -4
- data/SPEC.md +1 -1
- data/lib/yabeda/rack/queue/metric.rb +5 -1
- data/lib/yabeda/rack/queue/middleware.rb +3 -1
- data/lib/yabeda/rack/queue/version.rb +1 -1
- data/test/e2e/puma_integration_test.rb +2 -2
- data/test/yabeda/rack/queue/metric_test.rb +3 -2
- data/test/yabeda/rack/queue/middleware_test.rb +21 -0
- data/test/yabeda/rack/queue/railtie_test.rb +35 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a2460b8b476ceba45cccd0edd32320f133780bc01681d08bcf5fb162b7dd0cf4
|
|
4
|
+
data.tar.gz: 3b69c898a813804c2f8194fa9e5a84cf1508c1d3df2eb52096683e1b4612d09d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7b34b7083e9afb7c53825d8fd2645d74d36f4b6e9551885546de59f19d836199eb9cf3abc2a4a504d9844a52b468d157c1e6c1a3b7c1df62436b2286b1199271
|
|
7
|
+
data.tar.gz: c82d59eb210d12595a0c53a4330d004d0d7d4667fdb71101d0b2c2e4a017bc78b77f91ed312ceb6fae8bc68d2d28fb3ee6c7c761eb5020ffbedfc937af6b9788
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.1 - 2026-06-29
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Keep requests flowing if rack queue metric reporting fails, logging the error instead.
|
|
8
|
+
- Load `yabeda/railtie` when Rails appears after Yabeda was already required.
|
|
9
|
+
|
|
10
|
+
## 0.2.0 - 2026-03-09
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Renamed the histogram metric from `rack_queue_duration` to `duration` inside the `rack_queue` group.
|
|
15
|
+
- The Yabeda accessor is now `Yabeda.rack_queue.duration`.
|
|
16
|
+
- Adapters that prepend the group name, such as Prometheus, now expose the metric as `rack_queue_duration_seconds` instead of `rack_queue_rack_queue_duration_seconds`.
|
|
17
|
+
|
|
18
|
+
## 0.1.0 - 2026-03-08
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Initial release.
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
yabeda-rack-queue (0.1
|
|
4
|
+
yabeda-rack-queue (0.2.1)
|
|
5
5
|
yabeda (>= 0.14, < 1.0)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
@@ -114,7 +114,7 @@ CHECKSUMS
|
|
|
114
114
|
unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
|
|
115
115
|
unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
|
|
116
116
|
yabeda (0.14.0) sha256=bc517bf22d692ebd80a29fc9fd2246c257aaf92d10b2735a775e2419351a43bf
|
|
117
|
-
yabeda-rack-queue (0.1
|
|
117
|
+
yabeda-rack-queue (0.2.1)
|
|
118
118
|
|
|
119
119
|
BUNDLED WITH
|
|
120
120
|
4.0.3
|
data/README.md
CHANGED
|
@@ -12,7 +12,7 @@ High queue time means your app is too busy. It cannot take new requests. That is
|
|
|
12
12
|
|
|
13
13
|
Load balancers can add a header to each request. The header records when the request arrived. Common headers are `X-Request-Start` and `X-Queue-Start`.
|
|
14
14
|
|
|
15
|
-
This middleware reads that header. It subtracts the header's timestamp from the current time. Then it reports that value as `rack_queue.
|
|
15
|
+
This middleware reads that header. It subtracts the header's timestamp from the current time. Then it reports that value as `rack_queue.duration`.
|
|
16
16
|
|
|
17
17
|
> [!NOTE]
|
|
18
18
|
> If neither header is present, no measurement is taken. The request passes through unchanged.
|
|
@@ -55,14 +55,16 @@ config.middleware.use Yabeda::Rack::Queue::Middleware
|
|
|
55
55
|
|
|
56
56
|
| Name | Group | Type | Unit |
|
|
57
57
|
|------|-------|------|------|
|
|
58
|
-
| `
|
|
58
|
+
| `duration` | `rack_queue` | histogram | seconds |
|
|
59
59
|
|
|
60
60
|
Access it in code:
|
|
61
61
|
|
|
62
62
|
```ruby
|
|
63
|
-
Yabeda.rack_queue.
|
|
63
|
+
Yabeda.rack_queue.duration
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
With adapters that prepend the group name, such as Prometheus, this becomes `rack_queue_duration_seconds`.
|
|
67
|
+
|
|
66
68
|
Histogram buckets: 1 ms, 5 ms, 10 ms, 25 ms, 50 ms, 100 ms, 250 ms, 500 ms, 1 s, 2.5 s, 5 s, 10 s, 30 s, 60 s.
|
|
67
69
|
|
|
68
70
|
## Header formats
|
|
@@ -93,7 +95,6 @@ The middleware accepts these keyword arguments:
|
|
|
93
95
|
| Argument | Default | Purpose |
|
|
94
96
|
|----------|---------|---------|
|
|
95
97
|
| `reporter:` | `YabedaReporter.new` | Writes the value to Yabeda. |
|
|
96
|
-
| `parser:` | `HeaderTimestampParser.new` | Parses the header timestamp. |
|
|
97
98
|
| `logger:` | stderr | Gets warning messages. |
|
|
98
99
|
| `clock:` | `Process.clock_gettime(CLOCK_REALTIME)` | Returns current time in seconds. |
|
|
99
100
|
|
data/SPEC.md
CHANGED
|
@@ -21,7 +21,7 @@ Linting uses standardrb.
|
|
|
21
21
|
|
|
22
22
|
| Name | Type | Group | Unit | Description |
|
|
23
23
|
|------|------|-------|------|-------------|
|
|
24
|
-
| `
|
|
24
|
+
| `duration` | histogram | `rack_queue` | seconds | Time a request waited in the upstream queue before reaching the application |
|
|
25
25
|
|
|
26
26
|
### Histogram Buckets
|
|
27
27
|
|
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
require "yabeda"
|
|
4
4
|
|
|
5
|
+
# Yabeda only loads its Railtie if Rails exists when Yabeda is first required.
|
|
6
|
+
# Puma plugins can require Yabeda before Rails, so retry when this gem loads.
|
|
7
|
+
require "yabeda/railtie" if defined?(::Rails::Railtie)
|
|
8
|
+
|
|
5
9
|
Yabeda.configure do
|
|
6
10
|
group :rack_queue do
|
|
7
|
-
histogram :
|
|
11
|
+
histogram :duration,
|
|
8
12
|
comment: "Time a request waited in the upstream queue before reaching the application",
|
|
9
13
|
unit: :seconds,
|
|
10
14
|
buckets: [0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30, 60]
|
|
@@ -9,7 +9,7 @@ module Yabeda
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
class YabedaReporter
|
|
12
|
-
def observe(value) = Yabeda.rack_queue.
|
|
12
|
+
def observe(value) = Yabeda.rack_queue.duration.measure({}, value)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def initialize(app, reporter: YabedaReporter.new, logger: nil, clock: nil)
|
|
@@ -32,6 +32,8 @@ module Yabeda
|
|
|
32
32
|
start = @parser.parse(env["HTTP_X_REQUEST_START"], now: now) ||
|
|
33
33
|
@parser.parse(env["HTTP_X_QUEUE_START"], now: now)
|
|
34
34
|
report_queue_time(env, now, start) if start
|
|
35
|
+
rescue => error
|
|
36
|
+
@logger.warn("rack queue metric failed: #{error.class}: #{error.message}")
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
def report_queue_time(env, now, request_start)
|
|
@@ -55,7 +55,7 @@ class PumaIntegrationTest < Minitest::Test
|
|
|
55
55
|
super
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
def
|
|
58
|
+
def test_records_duration_histogram_via_yabeda_on_real_http_request
|
|
59
59
|
requested_queue_time_seconds = 0.12
|
|
60
60
|
request_start_ms = ((Time.now.to_f - requested_queue_time_seconds) * 1_000).to_i
|
|
61
61
|
uri = URI("http://127.0.0.1:#{@server.port}/")
|
|
@@ -66,7 +66,7 @@ class PumaIntegrationTest < Minitest::Test
|
|
|
66
66
|
|
|
67
67
|
assert_equal "200", response.code
|
|
68
68
|
|
|
69
|
-
metric = Yabeda.rack_queue.
|
|
69
|
+
metric = Yabeda.rack_queue.duration
|
|
70
70
|
measured = Yabeda::TestAdapter.instance.histograms.fetch(metric).fetch({})
|
|
71
71
|
|
|
72
72
|
assert_kind_of Float, measured
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
require "test_helper"
|
|
4
4
|
|
|
5
5
|
class MetricTest < Minitest::Test
|
|
6
|
-
def
|
|
7
|
-
metric = Yabeda.rack_queue.
|
|
6
|
+
def test_registers_duration_histogram_with_required_metadata
|
|
7
|
+
metric = Yabeda.rack_queue.duration
|
|
8
8
|
|
|
9
9
|
assert_instance_of Yabeda::Histogram, metric
|
|
10
|
+
assert_equal :duration, metric.name
|
|
10
11
|
assert_equal :rack_queue, metric.group
|
|
11
12
|
assert_equal :seconds, metric.unit
|
|
12
13
|
assert_equal "Time a request waited in the upstream queue before reaching the application", metric.comment
|
|
@@ -14,6 +14,12 @@ class CapturingReporter
|
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
class FailingReporter
|
|
18
|
+
def observe(_value)
|
|
19
|
+
raise NoMethodError, "undefined method `rack_queue' for Yabeda:Module"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
17
23
|
class CapturingLogger
|
|
18
24
|
attr_reader :warnings
|
|
19
25
|
|
|
@@ -144,6 +150,21 @@ class MiddlewareTest < Minitest::Test
|
|
|
144
150
|
assert_empty @reporter.values
|
|
145
151
|
end
|
|
146
152
|
|
|
153
|
+
def test_metric_reporting_errors_are_logged_and_do_not_break_request
|
|
154
|
+
middleware = Yabeda::Rack::Queue::Middleware.new(
|
|
155
|
+
@app,
|
|
156
|
+
reporter: FailingReporter.new,
|
|
157
|
+
clock: @clock,
|
|
158
|
+
logger: @logger
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
result = middleware.call("HTTP_X_REQUEST_START" => "t=1699999999.9")
|
|
162
|
+
|
|
163
|
+
assert_same @response, result
|
|
164
|
+
assert_equal 1, @app.called_count
|
|
165
|
+
assert_includes @logger.warnings.join("\n"), "rack queue metric failed: NoMethodError"
|
|
166
|
+
end
|
|
167
|
+
|
|
147
168
|
def test_drops_negative_queue_times_and_logs_warning
|
|
148
169
|
@middleware.call("HTTP_X_REQUEST_START" => "t=1700000000.1")
|
|
149
170
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
require "open3"
|
|
5
|
+
require "rbconfig"
|
|
6
|
+
|
|
7
|
+
class RailtieTest < Minitest::Test
|
|
8
|
+
def test_loads_yabeda_railtie_when_rails_appears_after_yabeda
|
|
9
|
+
script = <<~RUBY
|
|
10
|
+
require "bundler/setup"
|
|
11
|
+
require "yabeda"
|
|
12
|
+
|
|
13
|
+
module Rails
|
|
14
|
+
class Railtie
|
|
15
|
+
def self.config
|
|
16
|
+
@config ||= Config.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class Config
|
|
20
|
+
def after_initialize
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
require "yabeda/rack/queue"
|
|
27
|
+
|
|
28
|
+
abort "Yabeda::Rails::Railtie was not loaded" unless defined?(Yabeda::Rails::Railtie)
|
|
29
|
+
RUBY
|
|
30
|
+
|
|
31
|
+
stdout, stderr, status = Open3.capture3("bundle", "exec", RbConfig.ruby, "-Ilib", "-e", script)
|
|
32
|
+
|
|
33
|
+
assert status.success?, [stdout, stderr].join("\n")
|
|
34
|
+
end
|
|
35
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yabeda-rack-queue
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nate Berkopec
|
|
@@ -147,6 +147,7 @@ extensions: []
|
|
|
147
147
|
extra_rdoc_files: []
|
|
148
148
|
files:
|
|
149
149
|
- ".gitignore"
|
|
150
|
+
- CHANGELOG.md
|
|
150
151
|
- Gemfile
|
|
151
152
|
- Gemfile.lock
|
|
152
153
|
- LICENSE.txt
|
|
@@ -166,6 +167,7 @@ files:
|
|
|
166
167
|
- test/yabeda/rack/queue/metric_test.rb
|
|
167
168
|
- test/yabeda/rack/queue/middleware_performance_test.rb
|
|
168
169
|
- test/yabeda/rack/queue/middleware_test.rb
|
|
170
|
+
- test/yabeda/rack/queue/railtie_test.rb
|
|
169
171
|
- yabeda-rack-queue.gemspec
|
|
170
172
|
homepage: https://github.com/speedshop/yabeda-rack-queue
|
|
171
173
|
licenses:
|
|
@@ -190,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
190
192
|
- !ruby/object:Gem::Version
|
|
191
193
|
version: '0'
|
|
192
194
|
requirements: []
|
|
193
|
-
rubygems_version: 4.0.
|
|
195
|
+
rubygems_version: 4.0.10
|
|
194
196
|
specification_version: 4
|
|
195
197
|
summary: Yabeda middleware for HTTP request queue duration
|
|
196
198
|
test_files: []
|