Documentation
¶
Overview ¶
Package execution carries operation receipt and explicit execution metadata. Service disposal is separate from command completion and never commits command effects.
Index ¶
- Variables
- func ContextGuard() di.CaptureContext
- func NewContext(ctx context.Context, metadata Metadata) (context.Context, error)
- func ReceivedAt(ctx context.Context) (time.Time, bool)
- func Resolve[T any](ctx context.Context, scope *Scope) (T, error)
- func ResourcesAs[T Resources](ctx context.Context, scope *Scope) (T, error)
- func RunWithResources(ctx context.Context, open OpenResources, metadata Metadata, ...) (err error)
- func WithReceivedAt(ctx context.Context, receivedAt time.Time) context.Context
- type Metadata
- type OpenResources
- type PanicError
- type PendingScopeError
- type Resources
- type ResourcesJoiner
- type Scope
- func (s *Scope) CheckContext(ctx context.Context) error
- func (s *Scope) CheckOwner(ctx context.Context, owner di.ScopeOwner) error
- func (s *Scope) Close(ctx context.Context) (err error)
- func (s *Scope) Resolver() di.Resolver
- func (s *Scope) Resources() Resources
- func (s *Scope) Use(ctx context.Context, call func(context.Context, *Scope) error) (err error)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNoResolver identifies operation resources without a DI resolver. ErrNoResolver = errors.New("operation scope has no dependency-injection resources") // ErrScopeOwner identifies DI resources not owned by the configured provider. ErrScopeOwner = errors.New("operation scope resources belong to a different provider") )
var ( // ErrInvalidScope identifies an unconstructed scope. ErrInvalidScope = errors.New("invalid operation scope") // ErrScopeClosed identifies a scope that no longer admits work. ErrScopeClosed = errors.New("operation scope closed") // ErrScopeExpired identifies a retained callback view. ErrScopeExpired = errors.New("operation scope view expired") // ErrScopeJoinPending means Close has stopped admission but owned work has // not joined. Retry Close with a fresh budget; disposal is never restarted. ErrScopeJoinPending = errors.New("operation scope cleanup join pending") // ErrScopeView identifies an attempt to close a non-owning callback view. ErrScopeView = errors.New("operation scope view cannot close resources") // ErrIdentityChanged identifies changed principal/tenant values or presence. ErrIdentityChanged = errors.New("operation scope identity changed") )
var ErrInvalidArgument = errors.New("invalid execution argument")
ErrInvalidArgument identifies invalid openers/callbacks/contexts or negative cleanup timeouts.
var ErrResourceType = errors.New("incompatible operation resources")
ErrResourceType identifies an absent or incompatible resource holder.
Functions ¶
func ContextGuard ¶
func ContextGuard() di.CaptureContext
ContextGuard supplies Arc's immutable principal/tenant presence guard for container.WithContextGuard. Install it when building the optional Fundamentals container to protect factory-internal resolutions as well as Arc entry points. Capture/check reject nil contexts and cancellation; correlation and receipt may change. Checks support concurrent calls and never retain the captured context.
func NewContext ¶
NewContext explicitly installs metadata, generating missing correlation and receipt. Anonymous/NotSet values do not inherit parent authority. Cancellation remains with ctx.
func ReceivedAt ¶
ReceivedAt returns the receipt and its presence, including an explicitly installed zero time.
func Resolve ¶
Resolve resolves the exact registered T through the scope's guarded resolver. It validates adapter result types and nil values using Fundamentals contracts. No container is required; resources must implement di.Resolver for this path.
func ResourcesAs ¶
ResourcesAs checks lifetime/security and asserts the exact requested holder interface/type. It never resolves dependencies. Wrong/absent holders return ErrResourceType. Use within an admitted callback to prevent concurrent disposal.
func RunWithResources ¶
func RunWithResources(ctx context.Context, open OpenResources, metadata Metadata, cleanupTimeout time.Duration, call func(context.Context, *Scope) error) (err error)
RunWithResources executes synchronously with explicit operation metadata and fresh owned resources. The callback receives a non-closing view. Completion of the callback precedes disposal; disposal does not imply commit. Cleanup uses a bounded WithoutCancel context (zero means 30 seconds). Errors and PanicError diagnostics are joined; no goroutines are launched.
Example ¶
h := &holder{}
err := execution.RunWithResources(context.Background(), openHolder(h), execution.Metadata{}, 0,
func(ctx context.Context, scope *execution.Scope) error {
resources, err := execution.ResourcesAs[*holder](ctx, scope)
if err != nil {
return err
}
fmt.Println("closes during callback:", resources.closes.Load())
return nil
})
fmt.Println("error:", err)
fmt.Println("closes after callback:", h.closes.Load())
Output: closes during callback: 0 error: <nil> closes after callback: 1
Types ¶
type Metadata ¶
type Metadata struct {
// Principal is the explicit trusted actor; zero means anonymous.
Principal identity.Principal
// Tenant is the explicit tenant; zero means NotSet.
Tenant tenancy.ID
// CorrelationID identifies the operation; zero requests generation.
CorrelationID correlation.ID
// ReceivedAt records dispatch receipt; zero requests the current time.
ReceivedAt time.Time
}
Metadata contains values only, never a provider, scope, request, or cancellation ownership.
type OpenResources ¶
OpenResources opens cheap/lazy resources, not handler dependencies. A returned holder is owned even when accompanied by an error. Arc owns this operation seam; supplying a container is optional.
func ResourcesFrom ¶
func ResourcesFrom(factory di.ScopeFactory) OpenResources
ResourcesFrom adapts a borrowed factory to Arc's operation-opening seam. Each call opens a fresh DI scope; Arc owns its Close, never the factory's Close. Nil/typed-nil factories fail with ErrInvalidArgument and nil/typed-nil scopes with ErrResourceType. ScopeOwner, when implemented, must recognize the scope. A scope returned alongside an error remains owned for OpenScope's cleanup.
Example ¶
package main
import (
"context"
"fmt"
"github.com/cratis/arc.go/execution"
"github.com/cratis/arc.go/identity"
"github.com/cratis/arc.go/tenancy"
di "github.com/cratis/fundamentals.go/dependencyinjection"
"github.com/cratis/fundamentals.go/dependencyinjection/container"
)
func main() {
var registry container.Registry
if err := di.BindValue(®istry, "report service"); err != nil {
panic(err)
}
provider, err := registry.Build(container.WithContextGuard(execution.ContextGuard()))
if err != nil {
panic(err)
}
jobCtx := context.Background()
err = execution.RunWithResources(jobCtx, execution.ResourcesFrom(provider), execution.Metadata{Principal: identity.System("jobs"), Tenant: tenancy.Default()}, 0, func(ctx context.Context, scope *execution.Scope) error {
value, err := execution.Resolve[string](ctx, scope)
if err != nil {
return err
}
principal, _ := identity.PrincipalFrom(ctx)
tenant, _ := tenancy.TenantFrom(ctx)
fmt.Println(value, principal.ID(), tenant)
return nil
})
if err != nil {
panic(err)
}
if err := provider.Close(jobCtx); err != nil {
panic(err)
}
}
Output: report service [System] Default
type PanicError ¶
type PanicError struct {
// Value is the recovered panic value.
Value any
// Stack is a snapshot of the panicking goroutine's stack.
Stack []byte
}
PanicError records an application callback panic for local diagnostics only. Neither Value nor Stack is safe to expose to a client.
func (*PanicError) Error ¶
func (e *PanicError) Error() string
Error returns safe text without the panic value or stack.
type PendingScopeError ¶
type PendingScopeError struct {
// contains filtered or unexported fields
}
PendingScopeError retains an owning scope whenever Scope.Close has not joined. Callers of unary pipelines, RunWithResources and OpenScope must inspect this error with errors.As and finish Scope().Close with a fresh budget. Failed OpenScope still returns a nil scope with its error. The scope admits no new work. Closing it joins admitted uses before at-most-once disposal; after disposal starts, only an explicit resource join can resume. A caller that transfers this error also transfers cleanup ownership; ignoring it does not prove that resources have stopped.
func (*PendingScopeError) Error ¶
func (e *PendingScopeError) Error() string
Error returns the original cleanup and any opening diagnostics.
func (*PendingScopeError) Scope ¶
func (e *PendingScopeError) Scope() *Scope
Scope returns the retained owning scope for cleanup, never for execution.
func (*PendingScopeError) Unwrap ¶
func (e *PendingScopeError) Unwrap() error
Unwrap preserves opening, context and ErrScopeJoinPending error identities.
type Resources ¶
Resources is an application-owned holder for operation dependencies. Close must honor its context. Close is called at most once; its returned failure is final unless the holder explicitly implements ResourcesJoiner. A Fundamentals dependencyinjection.Scope satisfies it structurally; plain Go holders need no dependency-injection contract.
type ResourcesJoiner ¶
ResourcesJoiner explicitly separates one-time disposal initiation from joining owned cleanup. Scope calls Resources.Close at most once, then Join. Close must initiate cleanup even if its context expires; Join must not initiate disposal or repeat side effects. Join is serialized and may be called again after a context error or panic (which leaves completion unknown). A returned non-context Join result certifies that all owned cleanup has ended, including on failure; repeated Join after completion must return that outcome. Context errors from Close/Join mean incomplete waiting, not final disposal failures. Non-context Close/Join diagnostics, including recovered panics, remain inspectable alongside the eventual Join result. Scope starts no cleanup goroutine; the holder owns, cancels and joins its work.
type Scope ¶
type Scope struct {
// contains filtered or unexported fields
}
Scope guards one operation's security and resource lifetime. Zero is invalid. It is not an authorization verdict or transaction. Do not copy a Scope. Methods are concurrent-safe; application resources need their own concurrency contract. Use supplies non-closing, expiring views. No method starts a goroutine.
func BorrowScope ¶
BorrowScope guards resources without taking disposal ownership. Nil means an empty holder; typed nil is rejected. The caller remains responsible for keeping borrowed resources alive until all uses of the wrapper finish.
func OpenScope ¶
func OpenScope(ctx context.Context, open OpenResources) (*Scope, error)
OpenScope captures security before opening resources and rechecks it afterward. Nil openers and nil resources yield valid empty scopes; typed nils are invalid. Failed opening disposes acquired resources with a detached 30-second cleanup budget and joins errors. If cleanup is incomplete, PendingScopeError retains the scope for the caller to finish joining. Panics become PanicError.
func (*Scope) CheckContext ¶
CheckContext checks cancellation, security presence and lifetime. An admitted view remains usable while Close waits, but expires when its callback returns. Correlation and receipt changes do not change security ownership. Resources implementing di.ContextChecker are checked too, including borrowed DI scopes.
func (*Scope) CheckOwner ¶
CheckOwner admits an ownership check against a configured provider. Call it before using borrowed DI resources with that provider. It checks the underlying DI scope's identity, not the Arc wrapper or resolver facade. Nil/typed-nil owners fail with ErrInvalidArgument; non-DI or foreign resources fail with ErrScopeOwner. A factory without the optional ScopeOwner capability cannot supply this check; never infer ownership through interface equality.
func (*Scope) Close ¶
Close stops admission and joins admitted uses before closing owned resources at most once. Borrowed resources are never closed. Repeated calls return the recorded disposal outcome. A canceled admitted-use join leaves admission closed. ResourcesJoiner permits later calls to resume only the cleanup join, never Close initiation. Incomplete owned joins return PendingScopeError wrapping ErrScopeJoinPending; ordinary resource failures (including context errors without that capability) are final and cached. Cleanup is synchronous and cooperative. Never call an owning scope's Close from inside one of its own admitted callbacks.
func (*Scope) Resolver ¶
Resolver returns a guarded, non-closing resolver, never the raw resource holder. Each resolution is admitted through Use and checks security/cancellation before and after dependency code. A retained callback resolver expires with its view. Nil/zero scopes return a resolver failing with ErrInvalidScope; empty/plain resources fail with ErrNoResolver. Returned dependencies are borrowed and must not outlive the operation. Application use still needs its own concurrency contract.
func (*Scope) Resources ¶
Resources returns the borrowed holder or nil for invalid/expired scopes. It is a trusted adapter escape hatch, not a revocable security boundary. Use it only inside Use; never close it or retain it beyond the callback.