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

idle

package
v0.12.0 Latest Latest
Warning

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

Go to latest
Published: Oct 20, 2026 License: AGPL-3.0 Imports: 13 Imported by: 0

Documentation

Overview

Package idle stops, and later deletes, apps nobody uses (R-393 – R-398, issue #131).

Two halves. The Recorder takes the proxy's word that an app was used and writes it at most once a minute (R-394). The Pass runs on the leader, reads which apps have been idle long enough to be owed something, and does it: a notice, then 7 days later at the earliest a stop or a deletion (R-395).

Nothing here starts an app. An app stopped for being idle stays stopped until somebody starts it (R-396), and starting it clears the stop and every notice in the same write (migration 69), so this package never has to.

Index

Constants

View Source
const DefaultEvery = time.Hour

DefaultEvery is how often the pass runs. Days are the unit of every setting, so an hour late is nothing, and an hour is often enough that a notice lands the day it is owed.

View Source
const FlushEvery = time.Minute

FlushEvery is how often a replica writes the activity it has seen (R-394).

View Source
const NoticeDays = 7

NoticeDays is how long before a stop or a deletion the owner is told, and so the least time between the two (R-395 [P]).

Variables

This section is empty.

Functions

func ActionAt

func ActionAt(lastActivity, noticedAt time.Time, n int) time.Time

ActionAt is when an app idle since lastActivity, given notice at noticedAt, is stopped or deleted under a setting of n days: n days after its last activity, and never sooner than NoticeDays after the notice.

Types

type ActivityWriter

type ActivityWriter interface {
	RecordActivity(ctx context.Context, seen map[string]time.Time) error
}

ActivityWriter is where activity is written. *state.Activity is one.

type AppReader

type AppReader interface {
	ByID(ctx context.Context, appID string) (state.App, bool, error)
}

AppReader reads the app a deletion is for.

type Auditor

type Auditor interface {
	Write(ctx context.Context, e audit.Event) error
}

Auditor writes audit events.

type Deleter

type Deleter interface {
	Delete(ctx context.Context, app state.App, req appdelete.Request) (appdelete.Result, error)
}

Deleter deletes an app. *appdelete.Service is one.

type Notifier

type Notifier interface {
	Notify(ctx context.Context, n api.Notification) error
}

Notifier tells people things. subscription.Router is one.

type Pass

type Pass struct {
	Store   Store
	Apps    AppReader
	Deleter Deleter
	Policy  PolicyLoader

	// Notifier and Auditor are optional, and nil says nothing. Production
	// wires both: R-395 is a promise that nothing goes without warning.
	Notifier Notifier
	Auditor  Auditor

	Clock  clock.Clock
	Logger *zap.Logger

	// Every is how often Run runs a pass. Zero is DefaultEvery.
	Every time.Duration
}

Pass is the idle job.

func (*Pass) Once

func (p *Pass) Once(ctx context.Context)

Once runs one pass.

func (*Pass) Run

func (p *Pass) Run(ctx context.Context)

Run passes until ctx is canceled.

type PolicyLoader

type PolicyLoader interface {
	Load(ctx context.Context) (policy.Document, error)
}

PolicyLoader reads host policy.

type Recorder

type Recorder struct {
	Store  ActivityWriter
	Logger *zap.Logger
	// contains filtered or unexported fields
}

Recorder keeps which apps the proxy let a request through to, and writes them in one statement a minute.

In memory, because the request path must never wait on the database for this (R-394). A replica that stops loses at most a minute of it, which moves an app's idle clock by a minute against a setting counted in days.

func (*Recorder) Flush

func (r *Recorder) Flush(ctx context.Context)

Flush writes what has been seen since the last flush. On failure the batch is put back, merged with anything newer, for the next one.

func (*Recorder) Run

func (r *Recorder) Run(ctx context.Context)

Run flushes every FlushEvery until ctx is canceled, and once more on the way out so a clean stop loses nothing.

func (*Recorder) Touch

func (r *Recorder) Touch(appID string)

Touch records that a request reached appID now. One map write under a lock the flush holds only to swap the map out.

type Report

type Report struct {
	// StopDays and DeleteDays are the app's own: null is the install's, 0 is
	// off.
	StopDays   *int `json:"stop_days"`
	DeleteDays *int `json:"delete_days"`

	// InstallStopDays and InstallDeleteDays are host policy's.
	InstallStopDays   int `json:"install_stop_days"`
	InstallDeleteDays int `json:"install_delete_days"`

	// EffectiveStopDays and EffectiveDeleteDays are in force: the app's own
	// where set, the install's otherwise. 0 is off.
	EffectiveStopDays   int `json:"effective_stop_days"`
	EffectiveDeleteDays int `json:"effective_delete_days"`

	// LastActivityAt is the last request let through, deploy or start, or
	// the app's creation (R-394).
	LastActivityAt time.Time `json:"last_activity_at"`

	// StopsAt and DeletesAt are when Pando would act if nothing happens
	// before then; absent when it would not. Never sooner than a notice's
	// length after the owner is told (R-395).
	StopsAt   *time.Time `json:"stops_at,omitempty"`
	DeletesAt *time.Time `json:"deletes_at,omitempty"`

	// StoppedForIdle says Pando stopped it for being idle (R-396).
	StoppedForIdle bool `json:"stopped_for_idle"`
}

Report is an app's idle settings and what they mean for it now.

type Settings

type Settings struct {
	Store  SettingsStore
	Policy PolicyLoader
	Clock  clock.Clock
}

Settings reads and changes an app's idle settings.

func (*Settings) Report

func (s *Settings) Report(ctx context.Context, appID string) (Report, error)

Report reads an app's report.

func (*Settings) Set

func (s *Settings) Set(ctx context.Context, appID string, own state.IdleSettings) (Report, error)

Set replaces an app's own settings. Refused when a value is below zero, or when the delete in force would come no later than the stop in force.

type SettingsStore

type SettingsStore interface {
	IdleStatus(ctx context.Context, appID string) (state.IdleStatus, error)
	SetIdleSettings(ctx context.Context, appID string, s state.IdleSettings) error
}

SettingsStore reads and writes an app's idle settings.

type Store

type Store interface {
	IdleCandidates(ctx context.Context, d state.IdleDefaults, now time.Time) ([]state.IdleApp, error)
	SetIdleNotice(ctx context.Context, appID string, which state.IdleNotice, at *time.Time) error
	StopForIdle(ctx context.Context, appID string) (bool, error)
}

Store is the state the pass reads and writes.

Jump to

Keyboard shortcuts

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