memguard

package
v1.7.0 Latest Latest
Warning

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

Go to latest
Published: Jul 14, 2026 License: BSD-3-Clause Imports: 7 Imported by: 0

Documentation

Overview

Package memguard provides memory protection for the HTTP server, returning HTTP 429 when memory usage exceeds a configured threshold.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// ThresholdPct is the percentage of GOMEMLIMIT above which the pod is considered overloaded.
	//
	// 90 is a deliberately lenient default: GOMEMLIMIT is typically already
	// configured with headroom below the container's hard memory limit, so
	// stacking an aggressive threshold on top of it would cause readiness to
	// flap during ordinary GC-driven allocation bursts. Lower it if you want
	// to shed load earlier at the cost of more sensitivity to transient spikes.
	//
	// Values outside (0, 100] are treated as unset and fall back to 90, since a
	// zero or negative threshold would make IsOverloaded report overloaded
	// almost immediately and permanently.
	ThresholdPct int `default:"90" usage:"Percentage of GOMEMLIMIT above which the Guard signals memory overload"`
	// SamplingInterval is the interval between memory usage samples.
	// Smaller values increase responsiveness to spikes but add marginal overhead.
	SamplingInterval time.Duration `default:"500ms" usage:"Interval between memory usage samples"`
	// contains filtered or unexported fields
}

Config configures the memory-monitoring Guard. It can be embedded directly into any config struct in go-app.

type Guard

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

Guard monitors process memory usage and signals overload once consumption reaches the configured threshold.

Start is idempotent: calling it more than once is a no-op (logged as a warning), since the first call's sampling goroutine keeps running.

func New

func New(cfg Config) *Guard

New creates a Guard with the given configuration.

If GOMEMLIMIT is not configured (Go's default of math.MaxInt64, meaning "no limit"), the returned Guard is disabled: Start becomes a no-op, and IsOverloaded always returns false. This is deliberate — without a memory limit there's no threshold to compare against, so the Guard degrades to harmless rather than failing.

func (*Guard) Disabled

func (g *Guard) Disabled() bool

Disabled reports whether the Guard is disabled because GOMEMLIMIT is not configured. When disabled, Start is a no-op and IsOverloaded always returns false.

func (*Guard) IsOverloaded

func (g *Guard) IsOverloaded() bool

IsOverloaded returns true once memory usage has reached or exceeded the threshold. Always returns false when the Guard is disabled.

func (*Guard) Sample

func (g *Guard) Sample()

Sample reads "live" memory usage via runtime/metrics without causing a stop-the-world pause, and stores the result for IsOverloaded to compare against the threshold. It computes total - free - released to reflect only memory actually in use (inuse + stacks + metadata), discarding spans already released by the GC.

With plain total:bytes, the value never decreased after a GC (the heap moves from inuse to free, but the same virtual space stays mapped), leaving pods stuck as unready after memory spikes.

Start calls Sample on its own ticker; call it directly only if you need a custom sampling loop instead of Start's.

func (*Guard) SamplingInterval

func (g *Guard) SamplingInterval() time.Duration

SamplingInterval returns the interval Start uses between samples, after resolving Config.SamplingInterval's default (callers driving their own sampling loop instead of Start can use this instead of re-deriving the same default-resolution logic).

func (*Guard) Start

func (g *Guard) Start(ctx context.Context)

Start launches a goroutine that samples memory usage at the configured interval. The goroutine exits when ctx is canceled. If the Guard is disabled, Start returns immediately without starting a goroutine.

Calling Start more than once on the same Guard is a no-op past the first call: two sampling goroutines would race on the same internal metrics.Sample slice, so the second (and any later) call logs a warning and returns instead, leaving the original goroutine as the sole sampler.

type Overloader

type Overloader interface {
	IsOverloaded() bool
}

Overloader is implemented by any type that monitors system overload.

Jump to

Keyboard shortcuts

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