httpcache

package
v0.2.4 Latest Latest
Warning

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

Go to latest
Published: Jul 7, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package httpcache provides a caching http.RoundTripper that sits beneath the providers: they use an ordinary *http.Client and never manage caching themselves. Cacheable GET responses are memoised for the run and concurrent identical requests are coalesced, so a hundred markers pointing at the same upstream cause a single round trip. Cache hits make no network call at all, which is also the most effective way to stay within an API's rate limit.

The cache is keyed by method, URL, Authorization, Accept, and (for cacheable non-GET requests) the body, and stores full responses including their validators (ETag, Last-Modified), leaving room for a disk-backed Store and conditional revalidation behind the same seam.

The RFC 9111 semantics are implemented selectively, scoped to a short-lived CLI talking to known APIs: no-store is honored, but the no-cache and must-revalidate directives and the Age header are deliberately ignored, and Vary is subsumed by keying on the headers that matter here (Authorization, Accept).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EnableSharedDisk added in v0.1.1

func EnableSharedDisk(dir string) error

EnableSharedDisk opens the disk store rooted at dir and layers it under every client built by New. The command layer calls it once, so all providers share one handle. Clients already built are covered too - their disk tier is a lazy delegate, so enabling works whenever it happens during startup.

func New

func New(opts ...Option) *http.Client

New returns an *http.Client whose transport caches and coalesces GET requests. Providers use the returned client like any other and remain unaware of the cache.

func NewBaseTransport added in v0.1.12

func NewBaseTransport() http.RoundTripper

NewBaseTransport clones the default transport but caps connection setup, so an unreachable host fails fast instead of hanging on the OS default. It is the default base for New; pass it as the innermost transport when composing via WithTransport, so the dial caps still apply.

func WithCacheableRequest added in v0.1.3

func WithCacheableRequest(ctx context.Context, fallbackFreshness time.Duration) context.Context

WithCacheableRequest marks an idempotent non-GET request as eligible for the HTTP cache. When the origin does not provide validators or freshness headers, fallbackFreshness supplies a short freshness window for cross-run reuse.

Types

type DiskStore added in v0.1.1

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

DiskStore is a cross-run Store holding one JSON-encoded entry per file, named by the cache key (a hex SHA-256, so no escaping is needed). Writes are atomic, so concurrent runs race benignly - last write wins. The disk tier is best-effort: read and write failures are treated as misses, never errors.

func NewDiskStore added in v0.1.1

func NewDiskStore(dir string) (*DiskStore, error)

NewDiskStore opens the disk store rooted at dir, creating it if needed, and deletes entries not rewritten within the GC horizon.

func (*DiskStore) Get added in v0.1.1

func (s *DiskStore) Get(key string) (*Entry, bool)

Get returns the entry stored for key. A missing, unreadable, or corrupt file is a miss - corrupt files are deleted.

func (*DiskStore) Set added in v0.1.1

func (s *DiskStore) Set(key string, entry *Entry)

Set persists entry when a later run could serve it again: a 200 carrying a validator or positive freshness. Anything else would be pure disk waste - and a negative entry is stable only within a run, so it stays memory-only however long its origin-granted lifetime.

type Entry

type Entry struct {
	Status     int         `json:"status"`
	Header     http.Header `json:"header"`
	Body       []byte      `json:"body"`
	StoredAt   time.Time   `json:"stored_at"`
	FreshUntil time.Time   `json:"fresh_until"`
}

Entry is a cached HTTP response, buffered so it can be replayed any number of times. The Header is retained in full, so the validators conditional revalidation needs (ETag, Last-Modified) are already present. The JSON tags serialize an entry for a disk-backed Store. An entry is immutable once constructed - replaying clones the Header and only reads the Body.

type LayeredStore added in v0.1.1

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

LayeredStore composes a run-scoped store over a cross-run one: Get checks mem first and promotes disk hits into it, Set writes both. The transport stays unaware of the layering - it only sees a Store.

func NewLayeredStore added in v0.1.1

func NewLayeredStore(mem, disk Store) *LayeredStore

NewLayeredStore returns a store reading through mem to disk.

func (*LayeredStore) Get added in v0.1.1

func (l *LayeredStore) Get(key string) (*Entry, bool)

Get returns the entry for key from the first layer holding it.

func (*LayeredStore) Set added in v0.1.1

func (l *LayeredStore) Set(key string, entry *Entry)

Set stores entry in both layers.

type MemStore

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

MemStore is a concurrency-safe, in-memory Store. It lives for as long as the transport that holds it, which for a CLI run means the whole run.

func NewMemStore

func NewMemStore() *MemStore

NewMemStore returns an empty in-memory store.

func (*MemStore) Get

func (m *MemStore) Get(key string) (*Entry, bool)

Get returns the entry for key, if present.

func (*MemStore) Set

func (m *MemStore) Set(key string, entry *Entry)

Set stores entry under key.

type Option

type Option func(*config)

Option configures the client returned by New.

func WithErrorBackoff added in v0.1.1

func WithErrorBackoff(d time.Duration) Option

WithErrorBackoff sets how long a fetch error is replayed to further requests for the same key before the fetch is retried. A non-positive value disables the backoff.

func WithMaxEntryBytes added in v0.1.1

func WithMaxEntryBytes(n int64) Option

WithMaxEntryBytes sets the largest response body the cache will buffer. A non-positive value disables response-body caching.

func WithStore

func WithStore(s Store) Option

WithStore sets the cache backend (default: an in-memory MemStore). This is the seam for a disk-backed, cross-run store.

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets the client's total per-request timeout.

func WithTransport

func WithTransport(rt http.RoundTripper) Option

WithTransport sets the underlying transport the cache wraps on a miss. Compose a rate-limit-aware transport here so cache hits never consume rate limit.

type Stats added in v0.1.1

type Stats struct {
	Requests    int64
	Hits        int64
	Revalidated int64
	Coalesced   int64
	Replayed    int64
}

Stats is a snapshot of transport activity: requests that reached the network, cache hits served without one, conditional revalidations answered 304, singleflight-coalesced callers, and failures replayed by the error backoff.

func Snapshot added in v0.1.1

func Snapshot() Stats

Snapshot returns the process-wide transport totals so far.

type Store

type Store interface {
	Get(key string) (*Entry, bool)
	Set(key string, entry *Entry)
}

Store is the cache backend behind the transport. The default is in-memory and run-scoped; a disk-backed store for cross-run reuse can be supplied via WithStore without any change to providers or the transport.

type Transport

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

Transport is the caching http.RoundTripper. Non-GET requests pass straight through; GET requests are served from the store while fresh, revalidated with a conditional request when stale but carrying a validator, and otherwise fetched - concurrent identical fetches share a single round trip, and a fetch error is replayed to further requests for the backoff window, so a dead host costs one connection timeout per window instead of one per caller.

func (*Transport) RoundTrip

func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements http.RoundTripper.

Jump to

Keyboard shortcuts

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