agentic examples

Composed Limits

Composed Limits: a real provider enforces BOTH a billed quota and a connection ceiling. quota.and(pool) - new this round - holds the two laws in one limiter, and the run proves each law bound the traffic in its own dimension: admissions per window AND concurrent in-flight.

Reliability & Recovery Round 7 Samuel Williams exit 0

source on github

bundle exec ruby examples/composed_limits.rb

a real captured run

COMPOSED LIMITS: 12 calls x 50ms, quota 6/200ms AND pool of 2

  window 1 (  0-200ms): ######   6 admitted (quota allows 6)
  window 2 (200-400ms): ######   6 admitted (quota allows 6)

  pool high-water:  2 of 2 - the socket law held
  quota high-water: 6 concurrent (window law measures admissions, not flight)

which law binds? the pool could clear ~8 per window (2 lanes x 4
service times) but the quota admits only 6 - so the QUOTA is the
binding constraint, and the chart shows it: exactly 6 per window.
raise the quota and the pool becomes the wall. composition enforces
both laws and the windows tell you which one is throttling you.

ordering note: quota.and(pool) spends quota BEFORE waiting for a
socket - correct, because sockets are scarce and quota refills on a
clock. the reverse order would hold a connection hostage while
waiting for the meter.

source

# frozen_string_literal: true

# Composed Limits: a real provider enforces BOTH a billed quota and a
# connection ceiling. quota.and(pool) - new this round - holds the two
# laws in one limiter, and the run proves each law bound the traffic
# in its own dimension: admissions per window AND concurrent in-flight.
#
#   bundle exec ruby examples/composed_limits.rb
#
# Runs offline; 12 slow calls against quota 6/200ms and pool of 2.

require class="s">"bundler/setup"
require class="s">"agentic"
require class="s">"async"

REQUESTS = 12
CALL_TIME = 0.05

quota = Agentic:class="y">:RateLimit.new(6, per: 0.2) # billing law: 6 per 200ms
pool = Agentic:class="y">:RateLimit.new(2)            # socket law: 2 in flight
limit = quota.and(pool)                     # both, in that order

admissions = []
started = Process.clock_gettime(Process:class="y">:CLOCK_MONOTONIC)

Sync do
  REQUESTS.times.map {
    Async do
      limit.acquire do
        admissions << Process.clock_gettime(Process:class="y">:CLOCK_MONOTONIC) - started
        sleep(CALL_TIME)
      end
    end
  }.each(&class="y">:wait)
end

puts class="s">"COMPOSED LIMITS: #{REQUESTS} calls x #{(CALL_TIME * 1000).round}ms, " \
  class="s">"quota 6/200ms AND pool of 2"
puts

buckets = admissions.group_by { |t| (t / 0.2).floor }
buckets.sort.each do |window, hits|
  puts format(class="s">"  window %d (%3d-%3dms): %-8s %d admitted (quota allows 6)",
    window + 1, window * 200, (window + 1) * 200, class="s">"#" * hits.size, hits.size)
end

puts
puts format(class="s">"  pool high-water:  %d of %d - the socket law held", pool.high_water, pool.ceiling)
puts format(class="s">"  quota high-water: %d concurrent (window law measures admissions, not flight)", quota.high_water)
puts
puts class="s">"which law binds? the pool could clear ~8 per window (2 lanes x 4"
puts class="s">"service times) but the quota admits only 6 - so the QUOTA is the"
puts class="s">"binding constraint, and the chart shows it: exactly 6 per window."
puts class="s">"raise the quota and the pool becomes the wall. composition enforces"
puts class="s">"both laws and the windows tell you which one is throttling you."
puts
puts class="s">"ordering note: quota.and(pool) spends quota BEFORE waiting for a"
puts class="s">"socket - correct, because sockets are scarce and quota refills on a"
puts class="s">"clock. the reverse order would hold a connection hostage while"
puts class="s">"waiting for the meter."