R-1342: a restore copy under the stable-start watch is not deletable (D62 gap); an app removed during the watch raises no alarm — tests red first; commit only
gates / gates (push) Successful in 31s
gates / gates (push) Successful in 31s
This commit is contained in:
1 parent
6c72e3ff34
commit
652a690e5d
10 files changed
+231
-1
No files matched your search
@@ -71,9 +71,14 @@ func orNone(s string) string {
|
||||
// so and the kept copy is removed (the normal rule after a successful restore). A new restore of the app ends the watch
|
||||
// untouched.
|
||||
func (m *Manager) watchLateStart(stack, copyDir string, since time.Time, watch time.Duration) {
|
||||
m.setWatching(copyDir, true) // R-1342: the copy is the way back while the app may still start
|
||||
defer m.setWatching(copyDir, false)
|
||||
switch m.waitStableStart(stack, since, since.Add(watch)) {
|
||||
case stableAborted:
|
||||
return // a new restore of this app owns it now
|
||||
case stableRemoved:
|
||||
m.logger.Printf("[INFO] [backup] %s: the app was removed while the box waited for it to start — the watch ends (R-1342)", stack)
|
||||
return
|
||||
case stableNot:
|
||||
m.logger.Printf("[WARN] [backup] %s: still not running stably %s after its restore — the restore copy stays for support (%s) (R-1270)", stack, lateStartWatch, orNone(copyDir))
|
||||
return
|
||||
@@ -133,12 +138,26 @@ type containerSampler interface {
|
||||
ContainerSamples(name string) ([]ContainerSample, error)
|
||||
}
|
||||
|
||||
// StackRemovalReporter (R-1342) is the provider's optional answer to „was this app removed?" — true only when the app is
|
||||
// known and no longer installed. A watch that sees it ends quietly: an app the household removed did not „fail to
|
||||
// start". The production stackAdapter implements it (a compile-time assertion in cmd/controller/main.go).
|
||||
type StackRemovalReporter interface {
|
||||
StackRemoved(name string) bool
|
||||
}
|
||||
|
||||
// stackRemoved asks the provider; a provider without the answer never reads „removed".
|
||||
func (m *Manager) stackRemoved(stack string) bool {
|
||||
r, ok := m.stackProvider.(StackRemovalReporter)
|
||||
return ok && r.StackRemoved(stack)
|
||||
}
|
||||
|
||||
type stableResult int
|
||||
|
||||
const (
|
||||
stableYes stableResult = iota
|
||||
stableNot
|
||||
stableAborted
|
||||
stableRemoved // R-1342: the app was removed during the watch
|
||||
)
|
||||
|
||||
// stableSample is one look: ok, and the fingerprint (container id → restart count) a stable window must keep.
|
||||
@@ -201,6 +220,9 @@ func (m *Manager) waitStableFor(stack string, watchFrom, deadline time.Time, win
|
||||
if m.restoreBegunAfter(stack, watchFrom) {
|
||||
return stableAborted
|
||||
}
|
||||
if m.stackRemoved(stack) {
|
||||
return stableRemoved
|
||||
}
|
||||
ok, fp := m.stableSample(stack)
|
||||
switch {
|
||||
case !ok:
|
||||
@@ -226,13 +248,17 @@ func (m *Manager) releaseAfterStableStart(stack, kind string, undo *liveVolumeCo
|
||||
dir := undo.dir
|
||||
from := time.Now() // taken HERE, before the goroutine: a restore begun after this moment is a new one
|
||||
until := from.Add(stableReleaseWatch)
|
||||
m.setWatching(dir, true) // R-1342: „Törlés most" refuses the copy while the watch holds it
|
||||
go func() {
|
||||
defer m.setWatching(dir, false)
|
||||
switch m.waitStableStart(stack, from, until) {
|
||||
case stableYes:
|
||||
removeCopyDir(m, stack, dir)
|
||||
m.logger.Printf("[INFO] [backup] %s: ran stably for %s after its %s — the restore copy is released (R-1270)", stack, stableStartWindow, kind)
|
||||
case stableAborted:
|
||||
m.logger.Printf("[INFO] [backup] %s: a new restore began before the %s's start was stable — its restore copy stays for support (%s)", stack, kind, dir)
|
||||
case stableRemoved:
|
||||
m.logger.Printf("[INFO] [backup] %s: the app was removed during the stable-start check after its %s — no alarm; the restore copy, if the remove left it, is an unused one (%s) (R-1342)", stack, kind, dir)
|
||||
default:
|
||||
m.logger.Printf("[ERROR] [backup] %s: did not run stably within %s after its %s — the restore copy stays for support (%s) (R-1270)", stack, stableReleaseWatch, kind, dir)
|
||||
if m.restoreNotStartedNotify != nil {
|
||||
@@ -262,6 +288,8 @@ func (m *Manager) restoredAppStarted(stack string) error {
|
||||
return nil
|
||||
case stableAborted:
|
||||
return fmt.Errorf("a new restore of %s began", stack)
|
||||
case stableRemoved:
|
||||
return fmt.Errorf("%s was removed during the restore's start check", stack)
|
||||
}
|
||||
return fmt.Errorf("stack %s did not run stably for %s (it restarted or turned unhealthy) after restore", stack, verdictStableWindow)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user