Documentation
¶
Index ¶
- Variables
- func ComputePayloadHash(payload []byte) string
- func IsAmbiguous(err error) bool
- func MarkAmbiguous(err error) error
- type AmbiguousError
- type EffectReceipt
- type EffectRecord
- type EffectRequest
- type EffectStatus
- type Fencer
- type MemoryFencer
- type MemoryMetrics
- func (m *MemoryMetrics) RecordCommitted(ctx context.Context, tenantID, provider, operation string)
- func (m *MemoryMetrics) RecordExecuted(ctx context.Context, tenantID, provider, operation string)
- func (m *MemoryMetrics) RecordFailed(ctx context.Context, tenantID, provider, operation, reason string)
- func (m *MemoryMetrics) RecordFenced(ctx context.Context, tenantID, provider string)
- func (m *MemoryMetrics) RecordIdempotentHit(ctx context.Context, tenantID, provider, operation string)
- func (m *MemoryMetrics) RecordUnknown(ctx context.Context, tenantID, provider, operation string)
- type MemoryStore
- func (s *MemoryStore) CreateRecord(ctx context.Context, record *EffectRecord) error
- func (s *MemoryStore) ForceStatus(ctx context.Context, tenantID, effectID string, newStatus EffectStatus, ...) (*EffectRecord, error)
- func (s *MemoryStore) GetByIdempotencyKey(ctx context.Context, tenantID, agentID, key string) (*EffectRecord, error)
- func (s *MemoryStore) GetEffect(ctx context.Context, tenantID, effectID string) (*EffectRecord, error)
- func (s *MemoryStore) TransitionStatus(ctx context.Context, tenantID, effectID string, expectedStatus EffectStatus, ...) (*EffectRecord, error)
- type Metrics
- type NoopMetrics
- func (NoopMetrics) RecordCommitted(context.Context, string, string, string)
- func (NoopMetrics) RecordExecuted(context.Context, string, string, string)
- func (NoopMetrics) RecordFailed(context.Context, string, string, string, string)
- func (NoopMetrics) RecordFenced(context.Context, string, string)
- func (NoopMetrics) RecordIdempotentHit(context.Context, string, string, string)
- func (NoopMetrics) RecordUnknown(context.Context, string, string, string)
- type Provider
- type Service
- func (s *Service) ExecuteEffect(ctx context.Context, req *EffectRequest) (*EffectReceipt, error)
- func (s *Service) GetEffect(ctx context.Context, tenantID, effectID string) (*EffectRecord, error)
- func (s *Service) GetEffectByIdempotencyKey(ctx context.Context, tenantID, agentID, idempotencyKey string) (*EffectRecord, error)
- func (s *Service) RegisterProvider(provider Provider) error
- func (s *Service) ResolveUnknownEffect(ctx context.Context, tenantID, effectID string, forceStatus EffectStatus, ...) (*EffectReceipt, error)
- type Store
Constants ¶
This section is empty.
Variables ¶
var ( // ErrEffectNotFound indicates that the requested effect record does not exist. ErrEffectNotFound = errors.New("effect record not found") // ErrEffectFenced indicates that the attempt is stale or superseded and cannot execute effects. ErrEffectFenced = errors.New("effect rejected by fencing: attempt is stale or superseded") // ErrEffectUnknown indicates that the effect outcome is ambiguous and cannot be confirmed. // Automatic replay of an effect in UNKNOWN state is strictly prohibited. ErrEffectUnknown = errors.New("effect is in UNKNOWN state: outcome is ambiguous, automatic replay is strictly prohibited") // ErrEffectExecuting indicates that the effect is currently executing by another attempt or worker. ErrEffectExecuting = errors.New("effect is currently executing by another active attempt") // ErrPayloadMismatch indicates an idempotency key collision with a different payload hash. ErrPayloadMismatch = errors.New("idempotency key conflict: payload hash does not match previous request") // ErrProviderNotFound indicates that the requested external provider is not registered. ErrProviderNotFound = errors.New("effect provider not registered") // ErrProviderFailed indicates that the external provider execution failed with a definitive error. ErrProviderFailed = errors.New("effect provider execution failed") // ErrEffectExpired indicates that the effect request deadline has passed. ErrEffectExpired = errors.New("effect request deadline expired") // ErrInvalidRequest indicates that the effect request parameters failed validation. ErrInvalidRequest = errors.New("invalid effect request") // ErrEffectAlreadyCommitted indicates that the effect has already completed successfully. ErrEffectAlreadyCommitted = errors.New("effect has already been committed") // ErrInvalidStatusTransition indicates an invalid state transition on an effect record. ErrInvalidStatusTransition = errors.New("invalid effect status transition") )
Functions ¶
func ComputePayloadHash ¶
ComputePayloadHash calculates a standard SHA-256 hex digest of the payload bytes.
func IsAmbiguous ¶
IsAmbiguous tests whether an error represents an ambiguous execution outcome.
func MarkAmbiguous ¶
MarkAmbiguous wraps an error into an AmbiguousError.
Types ¶
type AmbiguousError ¶
type AmbiguousError struct {
Err error
}
AmbiguousError indicates that the outcome of an external operation cannot be determined. For instance, a network connection timed out or dropped after sending the HTTP payload, but before the server returned an acknowledgement.
func (*AmbiguousError) Error ¶
func (e *AmbiguousError) Error() string
func (*AmbiguousError) Unwrap ¶
func (e *AmbiguousError) Unwrap() error
type EffectReceipt ¶
type EffectReceipt struct {
EffectID string `json:"effect_id"`
TenantID string `json:"tenant_id"`
Status EffectStatus `json:"status"`
ProviderReceipt []byte `json:"provider_receipt,omitempty"`
StartedAt time.Time `json:"started_at"`
CompletedAt time.Time `json:"completed_at"`
AttemptID string `json:"attempt_id,omitempty"`
FencingToken int64 `json:"fencing_token"`
ResultHash string `json:"result_hash,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
}
EffectReceipt contains the durable execution outcome and proof of an external side effect.
type EffectRecord ¶
type EffectRecord struct {
Request EffectRequest `json:"request"`
Receipt *EffectReceipt `json:"receipt,omitempty"`
Status EffectStatus `json:"status"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Version int64 `json:"version"`
}
EffectRecord represents the persistent entity stored in the EffectStore.
type EffectRequest ¶
type EffectRequest struct {
ID string `json:"effect_id"`
TenantID string `json:"tenant_id"`
AgentID string `json:"agent_id"`
RunID string `json:"run_id,omitempty"`
AttemptID string `json:"attempt_id,omitempty"`
FencingToken int64 `json:"fencing_token"`
Provider string `json:"provider"`
Operation string `json:"operation"`
IdempotencyKey string `json:"idempotency_key"`
PayloadHash string `json:"payload_hash"`
Payload []byte `json:"payload,omitempty"`
Deadline *time.Time `json:"deadline,omitempty"`
TraceID string `json:"trace_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
EffectRequest defines a kernel-level request to produce an external side effect.
func (*EffectRequest) Validate ¶
func (r *EffectRequest) Validate() error
Validate checks essential constraints on the EffectRequest and populates ID and PayloadHash if missing.
type EffectStatus ¶
type EffectStatus string
EffectStatus represents the lifecycle state of an external side effect.
const ( // EffectStatusPending indicates the effect request has been registered but execution has not begun. EffectStatusPending EffectStatus = "PENDING" // EffectStatusExecuting indicates the effect is currently being dispatched to the external provider. EffectStatusExecuting EffectStatus = "EXECUTING" // EffectStatusCommitted indicates the effect was successfully executed and acknowledged by the external provider. // It is terminal and safe for idempotent replay (logical effect = 1). EffectStatusCommitted EffectStatus = "COMMITTED" // EffectStatusFailed indicates the external provider definitively rejected or failed the request. EffectStatusFailed EffectStatus = "FAILED" // EffectStatusUnknown indicates the request may or may not have reached or completed at the external provider // (e.g. timeout, connection reset, ambiguous ack). // CRITICAL: UNKNOWN must NEVER be automatically replayed or retried blindly. EffectStatusUnknown EffectStatus = "UNKNOWN" )
func (EffectStatus) IsTerminal ¶
func (s EffectStatus) IsTerminal() bool
IsTerminal returns true if the status is a completed terminal state.
type Fencer ¶
type Fencer interface {
ValidateFencingToken(ctx context.Context, tenantID, agentID, runID, attemptID string, fencingToken int64) error
}
Fencer validates whether an agent attempt's fencing token is current or stale.
type MemoryFencer ¶
type MemoryFencer struct {
// contains filtered or unexported fields
}
MemoryFencer provides an in-memory fencing registry for testing and development.
func NewMemoryFencer ¶
func NewMemoryFencer() *MemoryFencer
NewMemoryFencer creates a new in-memory fencer.
func (*MemoryFencer) SetActiveToken ¶
func (f *MemoryFencer) SetActiveToken(tenantID, agentID, runID string, token int64)
SetActiveToken sets the currently valid active fencing token for a tenant/agent/run tuple.
func (*MemoryFencer) ValidateFencingToken ¶
func (f *MemoryFencer) ValidateFencingToken(ctx context.Context, tenantID, agentID, runID, attemptID string, fencingToken int64) error
ValidateFencingToken checks if fencingToken is at least the active token. If active token is set and fencingToken < activeToken, ErrEffectFenced is returned.
type MemoryMetrics ¶
type MemoryMetrics struct {
ExecutedCount int64
CommittedCount int64
FailedCount int64
UnknownCount int64
FencedCount int64
IdempotentHits int64
// contains filtered or unexported fields
}
MemoryMetrics tracks counts in memory for test verification and monitoring.
func NewMemoryMetrics ¶
func NewMemoryMetrics() *MemoryMetrics
NewMemoryMetrics creates a new MemoryMetrics instance.
func (*MemoryMetrics) RecordCommitted ¶
func (m *MemoryMetrics) RecordCommitted(ctx context.Context, tenantID, provider, operation string)
func (*MemoryMetrics) RecordExecuted ¶
func (m *MemoryMetrics) RecordExecuted(ctx context.Context, tenantID, provider, operation string)
func (*MemoryMetrics) RecordFailed ¶
func (m *MemoryMetrics) RecordFailed(ctx context.Context, tenantID, provider, operation, reason string)
func (*MemoryMetrics) RecordFenced ¶
func (m *MemoryMetrics) RecordFenced(ctx context.Context, tenantID, provider string)
func (*MemoryMetrics) RecordIdempotentHit ¶
func (m *MemoryMetrics) RecordIdempotentHit(ctx context.Context, tenantID, provider, operation string)
func (*MemoryMetrics) RecordUnknown ¶
func (m *MemoryMetrics) RecordUnknown(ctx context.Context, tenantID, provider, operation string)
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore provides a concurrent-safe, in-memory implementation of Store.
func (*MemoryStore) CreateRecord ¶
func (s *MemoryStore) CreateRecord(ctx context.Context, record *EffectRecord) error
CreateRecord persists a new effect record in PENDING status.
func (*MemoryStore) ForceStatus ¶
func (s *MemoryStore) ForceStatus(ctx context.Context, tenantID, effectID string, newStatus EffectStatus, receipt *EffectReceipt) (*EffectRecord, error)
ForceStatus updates the status directly, used for administrative resolution of UNKNOWN state.
func (*MemoryStore) GetByIdempotencyKey ¶
func (s *MemoryStore) GetByIdempotencyKey(ctx context.Context, tenantID, agentID, key string) (*EffectRecord, error)
GetByIdempotencyKey retrieves an effect record by its idempotency key.
func (*MemoryStore) GetEffect ¶
func (s *MemoryStore) GetEffect(ctx context.Context, tenantID, effectID string) (*EffectRecord, error)
GetEffect retrieves an effect record by tenant and effect ID.
func (*MemoryStore) TransitionStatus ¶
func (s *MemoryStore) TransitionStatus(ctx context.Context, tenantID, effectID string, expectedStatus EffectStatus, newStatus EffectStatus, receipt *EffectReceipt) (*EffectRecord, error)
TransitionStatus performs an atomic Compare-And-Swap (CAS) on the effect status.
type Metrics ¶
type Metrics interface {
RecordExecuted(ctx context.Context, tenantID, provider, operation string)
RecordCommitted(ctx context.Context, tenantID, provider, operation string)
RecordFailed(ctx context.Context, tenantID, provider, operation, reason string)
RecordUnknown(ctx context.Context, tenantID, provider, operation string)
RecordFenced(ctx context.Context, tenantID, provider string)
RecordIdempotentHit(ctx context.Context, tenantID, provider, operation string)
}
Metrics records telemetry and counters for effect lifecycle events.
type NoopMetrics ¶
type NoopMetrics struct{}
NoopMetrics is a no-op implementation of Metrics.
func (NoopMetrics) RecordCommitted ¶
func (NoopMetrics) RecordExecuted ¶
func (NoopMetrics) RecordFailed ¶
func (NoopMetrics) RecordFenced ¶
func (NoopMetrics) RecordFenced(context.Context, string, string)
func (NoopMetrics) RecordIdempotentHit ¶
func (NoopMetrics) RecordUnknown ¶
type Provider ¶
type Provider interface {
Name() string
Execute(ctx context.Context, req *EffectRequest) ([]byte, error)
}
Provider defines the execution interface for an external effect provider.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service coordinates external effect execution, fencing, deduplication, and durable receipts.
func NewService ¶
NewService constructs an Effect Service.
func (*Service) ExecuteEffect ¶
func (s *Service) ExecuteEffect(ctx context.Context, req *EffectRequest) (*EffectReceipt, error)
ExecuteEffect executes an external side effect with strict fencing, idempotency, and receipt recording.
func (*Service) GetEffectByIdempotencyKey ¶
func (s *Service) GetEffectByIdempotencyKey(ctx context.Context, tenantID, agentID, idempotencyKey string) (*EffectRecord, error)
GetEffectByIdempotencyKey retrieves an effect record by idempotency key.
func (*Service) RegisterProvider ¶
RegisterProvider registers an external effect provider.
func (*Service) ResolveUnknownEffect ¶
func (s *Service) ResolveUnknownEffect(ctx context.Context, tenantID, effectID string, forceStatus EffectStatus, providerReceipt []byte, reason string) (*EffectReceipt, error)
ResolveUnknownEffect allows manual or administrative resolution of an effect in UNKNOWN status. This is used when external verification (e.g. contacting the external payment/webhook provider) has determined the actual outcome.
type Store ¶
type Store interface {
GetEffect(ctx context.Context, tenantID, effectID string) (*EffectRecord, error)
GetByIdempotencyKey(ctx context.Context, tenantID, agentID, idempotencyKey string) (*EffectRecord, error)
CreateRecord(ctx context.Context, record *EffectRecord) error
TransitionStatus(ctx context.Context, tenantID, effectID string, expectedStatus EffectStatus, newStatus EffectStatus, receipt *EffectReceipt) (*EffectRecord, error)
ForceStatus(ctx context.Context, tenantID, effectID string, newStatus EffectStatus, receipt *EffectReceipt) (*EffectRecord, error)
}
Store defines persistent storage and atomic state transitions for Effect records.