keepalive

package
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2026 License: AGPL-3.0 Imports: 4 Imported by: 0

Documentation

Overview

Package keepalive sends an "agent is active" signal to a provider- specific Listener whenever a backend event arrives. Each Tick carries the latest activity timestamp; the Listener decides what to do with it (renew a sandbox lease, write a TTL record, trigger shutdown after inactivity, …).

The package name describes the *active* mechanism — sending ticks while there's work — not the *goal*, which is the opposite: let the sandbox hibernate as soon as work is done. Sprites' problem is that it hibernates too eagerly; keepalive fights that. Other providers may have the opposite problem (never auto-shut), and a Listener for those would Tick into a shutdown decision instead. The Loop is agnostic.

Backpressure: callers (the host's subscriber loop) feed activity via Bump, which is a non-blocking send to a 1-slot channel. Bursts coalesce. Listeners therefore see at most one Tick per Bump, plus periodic ones at Interval. Any single surviving event refreshes lastActivity — a dropped event is harmless as long as one within the burst gets through.

Index

Constants

View Source
const (
	// DefaultInterval is the periodic Tick cadence. The Loop calls
	// Listener.Tick every Interval regardless of activity, so Listeners
	// that detect inactivity (compare time.Since(lastActivity) > X) get
	// a chance to act even without Bumps.
	DefaultInterval = 30 * time.Second

	// DefaultMinTickInterval is the debounce floor between consecutive
	// Ticks. A burst of Bumps within this window produces a single Tick.
	DefaultMinTickInterval = 5 * time.Second
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Listener        Listener
	Interval        time.Duration
	MinTickInterval time.Duration
	Log             *log.Logger
}

Config is the Loop's construction config. Listener is required; the rest defaults to Default* when zero. Construct via New.

type Listener

type Listener interface {
	Tick(ctx context.Context, lastActivity time.Time)
	Close(ctx context.Context) error
}

Listener is called by the Loop with the latest known activity timestamp on each tick. Each implementation decides what to do:

  • Sprites/Modal-style (renew lease): PUT while time.Since(lastActivity) < threshold.
  • Inactivity-detection (we kill): trigger shutdown when time.Since(lastActivity) > threshold.
  • Webhook forwarder: POST the timestamp; consumer decides.
  • TTL outbox: upsert a TTL record keyed on lastActivity.

Tick may fire with the zero time.Time before any Bump has happened. Implementations should treat zero as "no activity yet".

Tick should be cheap and non-blocking. It runs in the Loop's goroutine; a slow Tick blocks both the ticker and subsequent Bumps.

type Loop

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

Loop ticks the Listener on Interval and on Bump (debounced). Construct with New, drive activity via Bump, run with Run, stop with Stop.

func New

func New(cfg Config) *Loop

New constructs a Loop. Panics on missing Listener — fast failure beats a later nil deref. Run must be called to start the loop.

func (*Loop) Bump

func (l *Loop) Bump()

Bump signals that activity happened. Safe from any goroutine and non-blocking — if a Bump is already pending the new one coalesces into it. Callers in hot paths (the host's subscriber loop) call this for every event.

func (*Loop) Run

func (l *Loop) Run(ctx context.Context)

Run drives the Loop until ctx is canceled or Stop is called. Ticks the Listener on l.interval and on Bump (debounced to at most one per l.minTickInterval).

func (*Loop) Stop

func (l *Loop) Stop(ctx context.Context) error

Stop halts Run and calls Listener.Close. Safe to call multiple times concurrently: close(l.stop) and Listener.Close each fire exactly once; subsequent calls return the cached error from the first Close. If ctx fires before Run exits, Stop returns ctx.Err() without invoking Listener.Close — a subsequent Stop with a live ctx will still close.

Directories

Path Synopsis
Package exit implements a keepalive.Listener that shuts the process down after a period of inactivity — the "inactivity-detection (we kill)" listener anticipated by the keepalive package doc.
Package exit implements a keepalive.Listener that shuts the process down after a period of inactivity — the "inactivity-detection (we kill)" listener anticipated by the keepalive package doc.
Package noop provides a Listener that does nothing.
Package noop provides a Listener that does nothing.
Package sprites implements a keepalive.Listener backed by the Fly Sprites Tasks API (https://docs.sprites.dev/keeping-sprites-running/).
Package sprites implements a keepalive.Listener backed by the Fly Sprites Tasks API (https://docs.sprites.dev/keeping-sprites-running/).

Jump to

Keyboard shortcuts

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