mirror of
https://github.com/hanzoai/tasks.git
synced 2026-10-04 02:04:03 +00:00
## What changed? Add CHASM lifecycle paused state. Invalidates all pending logical tasks. ## Why? There are duplicate implementations in Libraries where authors have implemented their own statuses to act as a PAUSE state, preventing all tasks from executing. ## How did you test it? - [X] built - [X] run locally and tested manually - [X] covered by existing tests - [X] added new unit test(s) - [ ] added new functional test(s)
137 lines
3.7 KiB
Go
137 lines
3.7 KiB
Go
//go:generate mockgen -package $GOPACKAGE -source $GOFILE -destination component_mock.go
|
|
|
|
package chasm
|
|
|
|
import (
|
|
"context"
|
|
"reflect"
|
|
"strconv"
|
|
|
|
commonpb "go.temporal.io/api/common/v1"
|
|
)
|
|
|
|
type Component interface {
|
|
LifecycleState(Context) LifecycleState
|
|
|
|
// we may not need this in the beginning
|
|
mustEmbedUnimplementedComponent()
|
|
}
|
|
|
|
type TerminableComponent interface {
|
|
Component
|
|
|
|
// Terminate method is invoked by the chasm framework on an execution's root component when the execution
|
|
// needs to be forcefully terminated.
|
|
// Some examples include:
|
|
// - Execution state becomes too large.
|
|
// - Two running executions with the same businessID when namespace performs a force failover.
|
|
Terminate(MutableContext, TerminateComponentRequest) (TerminateComponentResponse, error)
|
|
}
|
|
|
|
type TerminateComponentRequest struct {
|
|
Identity string
|
|
Reason string
|
|
Details *commonpb.Payloads
|
|
RequestID string
|
|
}
|
|
|
|
type TerminateComponentResponse struct{}
|
|
|
|
// RootComponent is the interface that must be implemented by the top level component of a chasm execution.
|
|
// When the RootComponent's LifecycleState transitions to a closed state, the entire execution is considered closed,
|
|
// and will be cleaned up by the chasm framework after namespace's retention period. The BusinessID is also available for reuse.
|
|
//
|
|
// TODO: (not yet true) Visibility record will no longer be updated after RootComponent is closed.
|
|
type RootComponent interface {
|
|
TerminableComponent
|
|
|
|
// ContextMetadata returns execution metadata to propagate to the request context.
|
|
// When the ContextMetadataInterceptor is configured with setTrailer=true (history, matching),
|
|
// these keys are propagated via gRPC trailers. Keys defined in common/contextutil/metadata.go.
|
|
ContextMetadata(Context) map[string]string
|
|
}
|
|
|
|
// Embed UnimplementedComponent to get forward compatibility
|
|
type UnimplementedComponent struct{}
|
|
|
|
func (UnimplementedComponent) mustEmbedUnimplementedComponent() {}
|
|
|
|
var UnimplementedComponentT = reflect.TypeFor[UnimplementedComponent]()
|
|
|
|
// Shall it be named ComponentLifecycleState?
|
|
type LifecycleState int
|
|
|
|
const (
|
|
// Lifecycle states that are considered OPEN
|
|
//
|
|
// LifecycleStateCreated LifecycleState = 1 << iota
|
|
LifecycleStateRunning LifecycleState = 2 << iota
|
|
LifecycleStatePaused
|
|
|
|
// Lifecycle states that are considered CLOSED
|
|
//
|
|
LifecycleStateCompleted
|
|
LifecycleStateFailed
|
|
// LifecycleStateTerminated
|
|
// LifecycleStateTimedout
|
|
// LifecycleStateReset
|
|
)
|
|
|
|
func (s LifecycleState) IsClosed() bool {
|
|
return s >= LifecycleStateCompleted
|
|
}
|
|
|
|
func (s LifecycleState) IsPaused() bool {
|
|
return s == LifecycleStatePaused
|
|
}
|
|
|
|
func (s LifecycleState) String() string {
|
|
switch s {
|
|
case LifecycleStateRunning:
|
|
return "Running"
|
|
case LifecycleStatePaused:
|
|
return "Paused"
|
|
case LifecycleStateCompleted:
|
|
return "Completed"
|
|
case LifecycleStateFailed:
|
|
return "Failed"
|
|
default:
|
|
return strconv.Itoa(int(s))
|
|
}
|
|
}
|
|
|
|
type OperationIntent int
|
|
|
|
const (
|
|
OperationIntentProgress OperationIntent = 1 << iota
|
|
OperationIntentObserve
|
|
|
|
OperationIntentUnspecified = OperationIntent(0)
|
|
)
|
|
|
|
// The operation intent must come from the context
|
|
// as the handler may not pass the endpoint request as Input to,
|
|
// say, the chasm.UpdateComponent method.
|
|
// So similar to the chasm engine, handler needs to add the intent
|
|
// to the context.
|
|
type operationIntentCtxKeyType struct{}
|
|
|
|
var operationIntentCtxKey = operationIntentCtxKeyType{}
|
|
|
|
func newContextWithOperationIntent(
|
|
ctx context.Context,
|
|
intent OperationIntent,
|
|
) context.Context {
|
|
return context.WithValue(ctx, operationIntentCtxKey, intent)
|
|
}
|
|
|
|
func operationIntentFromContext(
|
|
ctx context.Context,
|
|
) OperationIntent {
|
|
intent, ok := ctx.Value(operationIntentCtxKey).(OperationIntent)
|
|
if !ok {
|
|
return OperationIntentUnspecified
|
|
}
|
|
return intent
|
|
}
|