Isolate runner finalization
This commit is contained in:
@@ -360,7 +360,7 @@ preserving every durable transition and failure boundary.
|
|||||||
|
|
||||||
## Stage 5 — Isolate Finalization And Simplify The Lifecycle Owner
|
## Stage 5 — Isolate Finalization And Simplify The Lifecycle Owner
|
||||||
|
|
||||||
**Status: Pending**
|
**Status: Completed**
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|
||||||
|
|||||||
@@ -71,10 +71,6 @@ func executePlanWithDependencies(ctx context.Context, cfg *config.Config, plan B
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
env := runtime.env
|
|
||||||
manifestPath := runtime.manifestPath
|
|
||||||
m := runtime.manifest
|
|
||||||
runID := runtime.identity.RunID
|
|
||||||
for _, selected := range runtime.stages {
|
for _, selected := range runtime.stages {
|
||||||
runtime.stageNames = append(runtime.stageNames, selected.Name())
|
runtime.stageNames = append(runtime.stageNames, selected.Name())
|
||||||
outcome, err := executeSelectedStage(runtime, selected)
|
outcome, err := executeSelectedStage(runtime, selected)
|
||||||
@@ -88,25 +84,7 @@ func executePlanWithDependencies(ctx context.Context, cfg *config.Config, plan B
|
|||||||
runtime.skipped = append(runtime.skipped, selected.Name())
|
runtime.skipped = append(runtime.skipped, selected.Name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return finalizeInvocation(runtime)
|
||||||
if containsStage(runtime.executed, "publish") {
|
|
||||||
if err := runPostPublishCleanup(ctx, env, manifestPath, m, runtime.executed, runtime.dependencies.removeScopedDir); err != nil {
|
|
||||||
return nil, persistPostPublishCleanupFailure(
|
|
||||||
ctx, env.ManifestStore, manifestPath, m,
|
|
||||||
fmt.Errorf("post-publish cleanup incomplete: %w", err),
|
|
||||||
runtime.dependencies.now(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &RunSummary{
|
|
||||||
SessionID: cfg.Session.SessionID,
|
|
||||||
RunID: runID,
|
|
||||||
ManifestPath: manifestPath,
|
|
||||||
StageNames: runtime.stageNames,
|
|
||||||
Executed: runtime.executed,
|
|
||||||
Skipped: runtime.skipped,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func stagesContainAny(stages []stage.Stage, names ...string) bool {
|
func stagesContainAny(stages []stage.Stage, names ...string) bool {
|
||||||
@@ -125,27 +103,6 @@ func stagesContainAny(stages []stage.Stage, names ...string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func persistPostPublishCleanupFailure(
|
|
||||||
ctx context.Context,
|
|
||||||
sessionStore manifest.Store,
|
|
||||||
sessionManifestPath string,
|
|
||||||
sessionManifest *manifest.Manifest,
|
|
||||||
operationErr error,
|
|
||||||
at time.Time,
|
|
||||||
) error {
|
|
||||||
if operationErr == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if sessionManifest != nil {
|
|
||||||
sessionManifest.RecordFailure(at, operationErr.Error())
|
|
||||||
}
|
|
||||||
// Cleanup may have deliberately removed the selected run directory. The
|
|
||||||
// committed remote snapshot remains authoritative, while the session
|
|
||||||
// manifest records the outstanding local cleanup for the next invocation.
|
|
||||||
sessionErr := sessionStore.Save(ctx, sessionManifestPath, sessionManifest)
|
|
||||||
return errors.Join(operationErr, wrapTerminalPersistenceError("save terminal session manifest", sessionErr))
|
|
||||||
}
|
|
||||||
|
|
||||||
func persistSessionTerminalFailure(
|
func persistSessionTerminalFailure(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
sessionStore manifest.Store,
|
sessionStore manifest.Store,
|
||||||
|
|||||||
62
internal/app/runner_finalization.go
Normal file
62
internal/app/runner_finalization.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gitea.maximumdirect.net/eric/narratio/internal/manifest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func finalizeInvocation(runtime *invocationRuntime) (*RunSummary, error) {
|
||||||
|
if containsStage(runtime.executed, "publish") {
|
||||||
|
if err := runPostPublishCleanup(
|
||||||
|
runtime.ctx,
|
||||||
|
runtime.env,
|
||||||
|
runtime.manifestPath,
|
||||||
|
runtime.manifest,
|
||||||
|
runtime.executed,
|
||||||
|
runtime.dependencies.removeScopedDir,
|
||||||
|
); err != nil {
|
||||||
|
return nil, persistPostPublishCleanupFailure(
|
||||||
|
runtime.ctx,
|
||||||
|
runtime.manifestStore,
|
||||||
|
runtime.manifestPath,
|
||||||
|
runtime.manifest,
|
||||||
|
fmt.Errorf("post-publish cleanup incomplete: %w", err),
|
||||||
|
runtime.dependencies.now(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &RunSummary{
|
||||||
|
SessionID: runtime.identity.SessionID,
|
||||||
|
RunID: runtime.identity.RunID,
|
||||||
|
ManifestPath: runtime.manifestPath,
|
||||||
|
StageNames: runtime.stageNames,
|
||||||
|
Executed: runtime.executed,
|
||||||
|
Skipped: runtime.skipped,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func persistPostPublishCleanupFailure(
|
||||||
|
ctx context.Context,
|
||||||
|
sessionStore manifest.Store,
|
||||||
|
sessionManifestPath string,
|
||||||
|
sessionManifest *manifest.Manifest,
|
||||||
|
operationErr error,
|
||||||
|
at time.Time,
|
||||||
|
) error {
|
||||||
|
if operationErr == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if sessionManifest != nil {
|
||||||
|
sessionManifest.RecordFailure(at, operationErr.Error())
|
||||||
|
}
|
||||||
|
// Cleanup may have deliberately removed the selected run directory. The
|
||||||
|
// committed remote snapshot remains authoritative, while the session
|
||||||
|
// manifest records the outstanding local cleanup for the next invocation.
|
||||||
|
sessionErr := sessionStore.Save(ctx, sessionManifestPath, sessionManifest)
|
||||||
|
return errors.Join(operationErr, wrapTerminalPersistenceError("save terminal session manifest", sessionErr))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user