Help us shape the future of Go! Take the 2026 Go Developer Survey

gateway

package
v0.2.11 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 19, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package gateway is the daemon half of the LLM gateway's server-side control plane (design 023): it reports governed spend to rysh-server, leases a slice of an org-wide allowance and enforces locally against that slice, and pulls central policy.

THE ONE RULE THIS PACKAGE EXISTS TO OBEY ---------------------------------------- The hot path never leaves the process. A per-request WAN call would put provider-latency-scale delay in front of every LLM request and turn a network blip into what looks like a provider outage (023 §4.2/G4). So:

  • Allow() reads local numbers only. No I/O, no locks held across a call, no blocking. Ever.
  • Everything that talks to the network — usage flushes, lease renewals, policy polls — runs on this package's own goroutine, off the request path.

INERT BY DEFAULT ---------------- Nothing here does anything unless BOTH `upstream.enabled` and the explicit `upstream.governance` opt-in are set. Enabled() is checked at every entry point, and TestLedgerClient_DisabledMakesNoNetworkCalls holds the line.

Index

Constants

View Source
const (
	FlushInterval = 10 * time.Second
	FlushMaxCalls = 256
)

Flush thresholds (design 023 §4.4): every 10 s or 256 metered calls, whichever comes first, and on shutdown.

View Source
const (
	PartitionLocal  = "local"  // fall back to the machine-local ceiling (default)
	PartitionStrict = "strict" // refuse
	PartitionOpen   = "open"   // allow
)

Partition modes (design 023 §4.3).

View Source
const (
	VerdictNoGovernance = "no_governance" // feature off
	VerdictLeased       = "leased"        // spending inside a valid lease
	VerdictExhausted    = "exhausted"     // the SERVER says the scope is out of budget
	VerdictLeaseSpent   = "lease_spent"   // local slice used up, renewal not back yet
	VerdictPartition    = "partition"     // no usable lease; partition mode decided
)

Verdicts explain why Allow answered as it did — for the log line, and for tests that must tell "out of budget" apart from "partitioned". Plain strings so LedgerClient satisfies proxy.LeaseGate without an adapter.

Variables

This section is empty.

Functions

This section is empty.

Types

type LeaseState

type LeaseState struct {
	Scope     string
	Granted   int64
	Spent     int64
	Expires   time.Time
	Ceiling   int64
	Remaining int64
	Exhausted bool
}

LeaseState is a snapshot for `##proxy status` / tests. Values only, no pointers into the client's state.

type LedgerClient

type LedgerClient struct {
	// contains filtered or unexported fields
}

LedgerClient owns all four flows in design 023 §4.1.

func New

func New(cfg config.UpstreamConfig, daemonID string, pub *msg.NATSPublisher) *LedgerClient

New builds a client. It is safe to construct one even when governance is off — every method is a no-op then, which keeps the call sites free of conditionals.

func (*LedgerClient) Allow

func (c *LedgerClient) Allow(tenant string) (bool, string)

Allow reports whether a tenant may spend right now.

IN-PROCESS AND NON-BLOCKING, ALWAYS. It reads a local number and may kick a renewal off on another goroutine; it never waits for one. This is the property design 023 §7's first risk row is about.

func (*LedgerClient) Enabled

func (c *LedgerClient) Enabled() bool

Enabled reports whether the control plane is active. Both switches must be on AND the connection details must be present: a half-configured upstream must not produce a client that fails a request per flush.

func (*LedgerClient) Flush

func (c *LedgerClient) Flush()

Flush publishes the pending rollups as one batch.

On a publish failure the rollups are put BACK and the sequence number is not consumed, so nothing is lost and the retry is byte-identical — which is exactly what the server's (daemon_id, seq) seen-set is built to absorb.

func (*LedgerClient) Leases

func (c *LedgerClient) Leases() []LeaseState

Leases snapshots every scope the daemon holds a lease for.

func (*LedgerClient) Policy

func (c *LedgerClient) Policy() ([]byte, time.Time)

Policy returns the last-known-good central document and when it was refreshed. Empty when none has ever been fetched.

func (*LedgerClient) PullPolicy

func (c *LedgerClient) PullPolicy(ctx context.Context) []byte

PullPolicy fetches the central policy document, using If-None-Match so an unchanged document costs a 304 (023 §4.7).

It returns the body when it CHANGED, nil otherwise. An unreachable server or an error response leaves the last-known-good document in place: an expired cache must not become an escape hatch around a policy (013's fail-closed rule applies to a central document exactly as it does to a local one).

func (*LedgerClient) Record

func (c *LedgerClient) Record(rec msg.MsgUsageRecord)

Record accumulates one metered call. It is called from the usage path, so it does nothing but arithmetic under a short lock.

The daemon keeps its own rollups regardless (023 §4.4): `##cost` stays a local, offline-capable view and this is a second, additive observer — never a replacement, and never a second source of truth for the local ledger.

func (*LedgerClient) SetPolicyHook

func (c *LedgerClient) SetPolicyHook(fn func([]byte))

SetPolicyHook installs the change callback. Call before Start.

func (*LedgerClient) Spend

func (c *LedgerClient) Spend(tenant string, tokens int64)

Spend records tokens against the current lease. Pure arithmetic; the renewal it may trigger happens on the next Allow.

func (*LedgerClient) Start

func (c *LedgerClient) Start()

Start runs the background loop: usage flushes, lease renewals, policy polls. It returns immediately, and is a no-op when governance is off.

func (*LedgerClient) Stop

func (c *LedgerClient) Stop()

Stop flushes what is pending and shuts the loop down. Safe to call twice.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL