idle

package
v0.17.0 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 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