v3.0.0-alpha.1 6fdddb8

app_state.go RawHistoryFolder

1package out
2
3import (
4	"context"
5
6	"github.com/bnema/gordon/internal/domain"
7)
8
9// AppState persists desired/active app state, reservations, intents,
10// operation journals, and ownership records. Implemented by the
11// atomic-file filesystem adapter; consumed by the apps use case.
12// All methods are safe for concurrent use within one process;
13// cross-process coordination is owned by the implementation
14// (store.lock flock). No secret values pass through this boundary.
15type AppState interface {
16	// Close releases the durable store and its process lock.
17	Close() error
18
19	// Recover completes committed-but-unmaterialized apply intents
20	// before any new mutation is accepted (recovery-before-mutation).
21	Recover(ctx context.Context) error
22
23	// LoadRecoveryInhibitions returns every durable recovery-inhibition
24	// record of one app. Boot and periodic recovery must refuse to
25	// start or restart an inhibited container ID.
26	LoadRecoveryInhibitions(ctx context.Context, app string) ([]domain.AppRecoveryInhibition, error)
27
28	// SaveRecoveryInhibition durably records one generation-scoped
29	// recovery inhibition. Repeated calls for the same
30	// (app, service, container ID) replace the existing record.
31	SaveRecoveryInhibition(ctx context.Context, inhibition domain.AppRecoveryInhibition) error
32
33	// ClearRecoveryInhibition drops the inhibition of one exact
34	// generation. Clearing an absent record is not an error.
35	ClearRecoveryInhibition(ctx context.Context, app, service, containerID string) error
36
37	// LoadCheckpoint returns the global reservation checkpoint.
38	LoadCheckpoint(ctx context.Context) (domain.AppStoreCheckpoint, error)
39
40	// AppExists reports whether the app has a live identity: desired
41	// state, active state, or an ownership incarnation. It never creates
42	// state. A retired app whose only remaining record is an operation
43	// journal does not exist (its own key still replays through
44	// ClaimOperation).
45	AppExists(ctx context.Context, app string) (bool, error)
46
47	// RegisterBackendBinds records Gordon-generated loopback backend
48	// binds (owner gordon-backend) in the global checkpoint. It fails
49	// closed on conflict with another app's desired/active/in-flight
50	// claim. Old binds stay claimed until ReleaseBackendBinds after
51	// verified withdrawal; same-app claims never self-conflict.
52	RegisterBackendBinds(ctx context.Context, binds []domain.AppListenerReservation) error
53
54	// ReleaseBackendBinds drops Gordon-generated loopback claims for one
55	// retired container. Unknown claims are ignored.
56	ReleaseBackendBinds(ctx context.Context, app, containerID string) error
57
58	// ListApps returns normalized names of apps with any state.
59	ListApps(ctx context.Context) ([]string, error)
60
61	// LoadDesired returns the latest accepted desired revision.
62	// ok is false when the app has no desired state.
63	LoadDesired(ctx context.Context, app string) (domain.AppDesiredRevision, bool, error)
64
65	// LoadRevision returns one immutable revision by id.
66	LoadRevision(ctx context.Context, app, revision string) (domain.AppDesiredRevision, error)
67
68	// ListRevisions returns revision ids ordered newest first.
69	ListRevisions(ctx context.Context, app string) ([]string, error)
70
71	// LoadActive returns the per-service effective state.
72	// ok is false when the app was never deployed.
73	LoadActive(ctx context.Context, app string) (domain.AppActive, bool, error)
74
75	// LoadIntent returns the durable stopped/running intent.
76	LoadIntent(ctx context.Context, app string) (domain.AppStopIntent, error)
77
78	// SaveIntent persists running/stopped intent.
79	SaveIntent(ctx context.Context, intent domain.AppStopIntent) error
80
81	// LoadOwnership returns the ownership record (zero value when absent).
82	LoadOwnership(ctx context.Context, app string) (domain.AppOwnership, error)
83
84	// SaveOwnership persists the ownership record.
85	SaveOwnership(ctx context.Context, ownership domain.AppOwnership) error
86
87	// StageApply writes a staged intent containing the full candidate.
88	// No reservation or revision is visible until CommitApply.
89	StageApply(ctx context.Context, intent domain.AppApplyIntent) error
90
91	// CommitApply is the single atomic commit point: staged→committed.
92	CommitApply(ctx context.Context, app, intentID string) error
93
94	// MaterializeApply finishes a committed intent: revision file,
95	// desired pointer, reservation checkpoint update, intent→applied.
96	// Idempotent by content hash; safe to replay after a crash.
97	MaterializeApply(ctx context.Context, app, intentID string) error
98
99	// LoadIntent returns one apply intent by id.
100	LoadApplyIntent(ctx context.Context, app, intentID string) (domain.AppApplyIntent, error)
101
102	// ListIntents returns apply intent ids for recovery scans.
103	ListIntents(ctx context.Context, app string) ([]string, error)
104
105	// CollectGarbage removes staged orphans, applied intents, and
106	// unreferenced revisions beyond retention. Referenced revisions
107	// (desired/active/in-flight) are never evicted.
108	CollectGarbage(ctx context.Context, app string, inFlight []string) error
109
110	// SaveOperation persists an operation journal record atomically.
111	SaveOperation(ctx context.Context, op domain.AppOperation) error
112
113	// ClaimOperation is the single atomic check-and-write point for one
114	// mutation request key. Absent key: the candidate is persisted as an
115	// in-flight journal and claimed is true. Same key with the same
116	// request identity: the stored journal is returned and claimed is
117	// false, meaning the caller must not execute the request's effects
118	// again. Same key with a different request identity:
119	// ErrAppStateConflict. Absent key for an app with no desired, active,
120	// or ownership incarnation: ErrAppNotFound, writing nothing. A
121	// concurrent claim of the same key never creates a second journal.
122	ClaimOperation(ctx context.Context, candidate domain.AppOperation) (existing domain.AppOperation, claimed bool, err error)
123
124	// LoadOperation returns one operation journal record.
125	LoadOperation(ctx context.Context, app, opID string) (domain.AppOperation, error)
126
127	// LoadLatestOperation returns the most recently started operation.
128	LoadLatestOperation(ctx context.Context, app string) (domain.AppOperation, bool, error)
129
130	// SaveActive persists the per-service effective state.
131	SaveActive(ctx context.Context, active domain.AppActive) error
132
133	// RetireApp atomically ends an app's incarnation: it archives the
134	// live ownership record with every resource marked retained, drops
135	// the live ownership record, resets the app UUID so a reapply
136	// allocates a new incarnation, and clears desired, active, intent,
137	// staged intents, and revisions. Retained resources stay protected
138	// by the archived record and can never be adopted by a name reuse.
139	RetireApp(ctx context.Context, app string) error
140}
141
142// AppStateReader is the ACTIVE/intent subset read paths need.
143// Narrower than AppState so read paths never gain write access.
144type AppStateReader interface {
145	ListApps(ctx context.Context) ([]string, error)
146	LoadActive(ctx context.Context, app string) (domain.AppActive, bool, error)
147	LoadIntent(ctx context.Context, app string) (domain.AppStopIntent, error)
148}
149
150// AppTrafficRefresher is the app-facing traffic contract: one serialized
151// HTTP/L4 publish boundary that supports both fail-closed withdrawal of
152// one service and full publication of current verified state. Both
153// operations read the latest validated config at call time and are
154// serialized against reload and other rebuilds so a stale config can
155// never win. WithdrawService must leave no forwarding for the named
156// service once it returns nil; failing loudly is preferred to leaving
157// stale L4 forwarding behind.
158type AppTrafficRefresher interface {
159	// RebuildTraffic re-projects verified ACTIVE state and applies the
160	// full HTTP/L4 graph.
161	RebuildTraffic(ctx context.Context) error
162	// WithdrawService publishes the current graph without the named
163	// app service, so a dead or unverified backend stops receiving
164	// traffic. A nil return means stale forwarding is proven disabled.
165	WithdrawService(ctx context.Context, app, service string) error
166	// WithdrawServiceState drops the named service's recorded backend
167	// binds in ACTIVE without applying the graph. It is the canonical
168	// state-only withdrawal: ready-path failures use it when the
169	// caller already owns publication (or none is due), so no second
170	// routing-state write races the serialized WithdrawService path.
171	WithdrawServiceState(ctx context.Context, app, service string) error
172}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close