Class: OpenReceive::Server::Swap::SwapProviderWeightBudget

Inherits:
Object
  • Object
show all
Defined in:
lib/openreceive/server/swap/weight_budget.rb

Overview

Ruby port of packages/js/node/src/swap/weight-budget.ts: a disposable per-process request guard; the provider remains the global rate-limit authority.

Constant Summary collapse

WINDOW_SECONDS =
60
SOFT_CAP =
200
CREATE_GATE =
150
CREATE_WEIGHT =
50
DEFAULT_WEIGHT =
1
BACKOFF_SECONDS =
60

Instance Method Summary collapse

Constructor Details

#initialize(provider_id, clock) ⇒ SwapProviderWeightBudget

Returns a new instance of SwapProviderWeightBudget.



37
38
39
40
41
42
43
44
# File 'lib/openreceive/server/swap/weight_budget.rb', line 37

def initialize(provider_id, clock)
  @provider_id = provider_id
  @clock = clock
  @window_start = clock.call
  @used = 0
  @backoff_until = nil
  @monitor = Monitor.new
end

Instance Method Details

#mark_rate_limitedObject



69
70
71
72
73
74
75
76
# File 'lib/openreceive/server/swap/weight_budget.rb', line 69

def mark_rate_limited
  @monitor.synchronize do
    now = @clock.call
    @used = [@used, SOFT_CAP].max
    @backoff_until = now + BACKOFF_SECONDS
  end
  nil
end

#reserve(path) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/openreceive/server/swap/weight_budget.rb', line 50

def reserve(path)
  @monitor.synchronize do
    roll_window
    now = @clock.call
    cost = weight_for_path(path)
    limit = gate(path)
    if !@backoff_until.nil? && @backoff_until > now
      deny(path, "backoff", cost, limit,
           "Swap provider API is in backoff until #{@backoff_until}.")
    end
    if @used + cost > limit
      deny(path, "exhausted", cost, limit,
           "Swap provider API weight budget exhausted (#{@used}+#{cost} > #{limit}).")
    end
    @used += cost
  end
  nil
end

#weight_for_path(path) ⇒ Object



46
47
48
# File 'lib/openreceive/server/swap/weight_budget.rb', line 46

def weight_for_path(path)
  path == "create" ? CREATE_WEIGHT : DEFAULT_WEIGHT
end