No release in over 3 years
Rack middleware that measures HTTP request queue duration from upstream headers and reports it to Yabeda as a histogram metric.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

>= 0.4, < 1.0
>= 2.14, < 3.0
>= 5.22, < 6.0
>= 6, < 8
>= 13.0
~> 1.44

Runtime

>= 0.14, < 1.0
 Project Readme

yabeda-rack-queue

Rack middleware that measures HTTP request queue time. It reports the result to Yabeda as a histogram.

What is queue time?

A request may wait before your app handles it. A proxy or load balancer (like Nginx or Heroku) causes this wait. This is called queue time.

High queue time means your app is too busy. It cannot take new requests. That is a sign you need more capacity.

How it works

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.

This middleware reads that header. It subtracts the header's timestamp from the current time. Then it reports that value as rack_queue.rack_queue_duration.

Note

If neither header is present, no measurement is taken. The request passes through unchanged.

Installation

Add to your Gemfile:

gem "yabeda-rack-queue"

Then run:

bundle install

Usage

Add the middleware to your Rack stack. You also need a Yabeda adapter. For example, use yabeda-prometheus.

require "yabeda/rack/queue"
require "yabeda/prometheus"

Yabeda.configure!

use Yabeda::Rack::Queue::Middleware
run MyRackApp

For Rails, add it in config/application.rb:

config.middleware.use Yabeda::Rack::Queue::Middleware

Metric

Name Group Type Unit
rack_queue_duration rack_queue histogram seconds

Access it in code:

Yabeda.rack_queue.rack_queue_duration

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.

Header formats

The middleware checks X-Request-Start first. If that header is absent, it tries X-Queue-Start.

Supported timestamp formats:

Format Example
Seconds (float) 1609459200.123
Milliseconds 1609459200123
Microseconds 1609459200123456
t= prefix t=1609459200.123

The middleware auto-detects the unit. It checks if the number fits a valid recent time.

Puma adjustment

Puma sets puma.request_body_wait (in milliseconds) in the Rack env. This records how long Puma spent reading the request body.

The middleware subtracts this value from queue time. Without this step, large bodies make queue time appear too long.

Configuration

The middleware accepts these keyword arguments:

Argument Default Purpose
reporter: YabedaReporter.new Writes the value to Yabeda.
parser: HeaderTimestampParser.new Parses the header timestamp.
logger: stderr Gets warning messages.
clock: Process.clock_gettime(CLOCK_REALTIME) Returns current time in seconds.

Example with a custom logger:

use Yabeda::Rack::Queue::Middleware, logger: Rails.logger

Requirements

  • Ruby >= 3.1.
  • yabeda >= 0.14, < 1.0.
  • A Yabeda adapter. For example: yabeda-prometheus.

Development

Run tests:

bundle exec rake test

Run the linter:

bundle exec standardrb

Contributing

Bug reports and pull requests are welcome at https://github.com/speedshop/yabeda-rack-queue.

License

MIT. See LICENSE.txt.