Observe claimed prepared executions

This commit is contained in:
2026-09-23 17:15:51 +00:00
parent 0e1ad784d1
commit 63bedf2a97
12 changed files with 279 additions and 11 deletions

View File

@@ -473,7 +473,8 @@ func (e *Engine) Prepare(ctx context.Context, req RunRequest) (*PreparedRun, err
// PrepareExecution returns the same error categories as [Engine.Prepare] and
// returns no handle on error. A nil Engine returns an error matching
// ErrInvalidConfig. The effective transient retry budget is frozen privately
// for RunPrepared and is absent from Details.
// for RunPrepared and is absent from Details. A supplied Observer is retained
// privately for RunPrepared; preparation itself emits no events.
func (e *Engine) PrepareExecution(ctx context.Context, req RunRequest) (*PreparedExecution, error) {
if e == nil || e.internal == nil {
return nil, fmt.Errorf("%w: engine is nil", ErrInvalidConfig)
@@ -590,7 +591,12 @@ func (e *Engine) run(ctx context.Context, req RunRequest) (*RunResult, error) {
// content-validation rejection, including repair exhaustion, is returned in
// RunResult, not as an operational
// error. RunPrepared uses the retry choice frozen during PrepareExecution. An
// operational error returns no partial RunResult.
// operational error returns no partial RunResult. A retained Observer begins
// only after a successful atomic claim, with identities from the frozen
// snapshot, and receives a terminal event on normal return after public error
// mapping. Invalid, foreign, discarded, or reused handles emit no events.
// Callbacks run outside the handle and capacity locks; panics propagate and
// do not promise a terminal event.
func (e *Engine) RunPrepared(ctx context.Context, prepared *PreparedExecution) (*RunResult, error) {
if e == nil || e.internal == nil {
return nil, fmt.Errorf("%w: engine is nil", ErrInvalidConfig)
@@ -600,9 +606,21 @@ func (e *Engine) RunPrepared(ctx context.Context, prepared *PreparedExecution) (
if prepared != nil {
internal = prepared.internal
}
result, err := e.internal.RunPrepared(ctx, internal)
var recorder *observation.Recorder
result, err := e.internal.RunPrepared(observation.WithClaimSink(ctx, &recorder), internal)
if err != nil {
return nil, mapPublicError(err)
mapped := mapPublicError(err)
if recorder != nil {
terminal := observedFinish(nil, mapped)
recorder.Finish(observation.FinishData{Outcome: terminal.Outcome, Failure: terminal.Failure,
StatusCode: terminal.StatusCode, RetriesExhausted: terminal.RetriesExhausted})
}
return nil, mapped
}
return fromDomainRunResult(result), nil
publicResult := fromDomainRunResult(result)
if recorder != nil {
terminal := observedFinish(publicResult, nil)
recorder.Finish(observation.FinishData{Outcome: terminal.Outcome})
}
return publicResult, nil
}