Watch
1
0
Fork
You've already forked pkg-proxy
1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-11-09 15:49:16 -05:00
pkg-proxy/internal/handler/upstream_held.go
Simon Chrzanowski 3935ccd6f7 Share upstream rate-limit holds across instances
Holds placed by the rate limit gate are written to a new upstream_holds
table, and each instance reads that table at most every two seconds and
refuses requests to a host any instance holds. Before, every replica had
to get its own 429 before it stopped sending.

Instances waiting on a fetch lease reread the holds when the fetch fails,
so when the holder was rate limited they answer 503 with its Retry-After
instead of each sending one more request to the limited host.
2026-10-25 17:34:08 +01:00

53 lines
1.5 KiB
Go

package handler
import (
"errors"
"math"
"net/http"
"strconv"
registryclient "github.com/git-pkgs/registries/client"
)
// writeUpstreamHeld answers a request the rate limit gate refused to send
// with 503 and the Retry-After the upstream asked for, and reports whether
// err was such a refusal.
func writeUpstreamHeld(w http.ResponseWriter, err error) bool {
var held *registryclient.HeldError
if !errors.As(err, &held) {
return false
}
secs := int(math.Ceil(held.RetryAfter.Seconds()))
if secs < 1 {
secs = 1
}
w.Header().Set("Retry-After", strconv.Itoa(secs))
http.Error(w, held.Error(), http.StatusServiceUnavailable)
return true
}
// UpstreamHolds reports whether requests to a URL's host are held by rate
// limiting. *registryclient.RateLimitGate and the shared gate in
// internal/httpclient implement it.
type UpstreamHolds interface {
// Held returns a *registryclient.HeldError while rawURL's host is held.
Held(rawURL string) error
}
// upstreamHeld returns the hold on rawURL's host, if any.
func (p *Proxy) upstreamHeld(rawURL string) error {
if p.RateLimits == nil {
return nil
}
return p.RateLimits.Held(rawURL)
}
// reloadUpstreamHolds rereads holds shared with other instances, when the
// gate shares them. It is called after another instance's fetch failed,
// since a 429 there will have placed a hold this instance may not have read
// yet.
func (p *Proxy) reloadUpstreamHolds() {
if r, ok := p.RateLimits.(interface{ Reload() }); ok {
r.Reload()
}
}