Files
promptkit/internal/usecase/operation_scope.go

37 lines
1.1 KiB
Go
Raw Normal View History

package usecase
import (
"context"
"errors"
"time"
)
// OperationScope owns an optional deadline and its invocation-specific cause.
type OperationScope struct {
Context context.Context
cancel context.CancelFunc
cause error
}
// NewOperationScope creates a child only when the selected duration is positive.
func NewOperationScope(parent context.Context, duration time.Duration) *OperationScope {
scope := &OperationScope{Context: parent, cancel: func() {}}
if duration > 0 {
scope.cause = errors.New("operation deadline")
scope.Context, scope.cancel = context.WithTimeoutCause(parent, duration, scope.cause)
}
return scope
}
// Finalize preserves the failure and marks it only when this scope expired.
func (s *OperationScope) Finalize(err error) error {
if err != nil && s.cause != nil && s.Context.Err() == context.DeadlineExceeded &&
errors.Is(err, s.Context.Err()) && context.Cause(s.Context) == s.cause {
return &OperationError{Category: ErrOperationTimeout, Cause: err}
}
return err
}
// Close releases the timer and associated child context.
func (s *OperationScope) Close() { s.cancel() }