mirror of
https://github.com/hanzoai/tasks.git
synced 2026-10-04 02:04:03 +00:00
## What changed? Added support for Nexus workflow update completion callbacks via CHASM. This allows a Nexus caller to be notified when a workflow update completes by attaching completion callbacks to the update request. ## Why? Nexus operations that target workflow updates need a way to receive completion notifications. Without this, a Nexus caller that sends an update has no async mechanism to learn when the update finishes. Completion callbacks enable the same async notification pattern that already exists for workflow-level Nexus operations. ## How did you test it? - [ ] built - [x] run locally and tested manually - [ ] covered by existing tests - [x] added new unit test(s) - [x] added new functional test(s) ## Potential risks Touches speculative workflow updates, they are always hard to reason about. Tried to compensate with lots of test coverage. Note: Needs this API PR https://github.com/temporalio/api/pull/742/changes --- > [!NOTE] > **High Risk** > Touches workflow update state machine and mutable state event handling to persist/trigger per-update callbacks, including close/retry/reset paths, which is complex and can affect correctness of update outcomes and callback delivery. > > **Overview** > Adds **workflow update completion callbacks** via CHASM so Nexus callers can register callbacks on `UpdateWorkflowExecution` and have them fired on update completion or workflow close. > > This introduces a `WorkflowUpdate` CHASM component with new `UpdateState` protobuf (including persisted `rejection_failure`), stores update callbacks under `Workflow.Updates`, and extends callback processing to handle *update-level* callbacks on update completion, rejection (including reset/reapply), and on run transitions (retry/timeout/continue-as-new) where update callbacks must fire even if workflow-level callbacks are inherited. > > It also adds dynamic config gates/limits (`EnableWorkflowUpdateCallbacks`, `MaxCallbacksPerUpdateID`), updates `DescribeWorkflow` to surface update callback triggers, extends mutable state/history builder APIs to carry per-update callback options in `WorkflowExecutionOptionsUpdated`, and adds `Update.AttachCallbacks` logic to persist/flush callbacks (including buffering while `stateSent`, request-id dedup, and stricter validation requiring `request_id` when callbacks are present). > > <sup>Reviewed by [Cursor Bugbot]() for commit 4484fee104d73344ef5370c468008440c7df1c6a. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> --------- Co-authored-by: long-nt-tran <[email protected]>
64 lines
2.7 KiB
Go
64 lines
2.7 KiB
Go
package chasm
|
|
|
|
import (
|
|
"time"
|
|
|
|
enumspb "go.temporal.io/api/enums/v1"
|
|
historypb "go.temporal.io/api/history/v1"
|
|
"go.temporal.io/server/common/nexus/nexusrpc"
|
|
)
|
|
|
|
// MSPointer is a special CHASM type which components can use to access their Node's underlying backend (i.e. mutable
|
|
// state). It is used to expose methods needed from the mutable state without polluting the chasm.Context interface.
|
|
// When deserializing components with fields of this type, the CHASM engine will set the value to its NodeBackend.
|
|
// This should only be used by the Workflow component.
|
|
type MSPointer struct {
|
|
backend NodeBackend
|
|
}
|
|
|
|
// NewMSPointer creates a new MSPointer instance.
|
|
func NewMSPointer(backend NodeBackend) MSPointer {
|
|
return MSPointer{
|
|
backend: backend,
|
|
}
|
|
}
|
|
|
|
// WorkflowRunTimeout returns the workflow run timeout duration. Returns 0 if no timeout is set.
|
|
func (m MSPointer) WorkflowRunTimeout() time.Duration {
|
|
return m.backend.GetExecutionInfo().GetWorkflowRunTimeout().AsDuration()
|
|
}
|
|
|
|
// AddHistoryEvent adds a history event via the underlying mutable state.
|
|
func (m MSPointer) AddHistoryEvent(t enumspb.EventType, setAttributes func(*historypb.HistoryEvent)) *historypb.HistoryEvent {
|
|
return m.backend.AddHistoryEvent(t, setAttributes)
|
|
}
|
|
|
|
// HasAnyBufferedEvent returns true if there is at least one buffered event that matches the provided filter.
|
|
func (m MSPointer) HasAnyBufferedEvent(filter func(*historypb.HistoryEvent) bool) bool {
|
|
return m.backend.HasAnyBufferedEvent(filter)
|
|
}
|
|
|
|
func (m MSPointer) GenerateEventLoadToken(event *historypb.HistoryEvent) ([]byte, error) {
|
|
return m.backend.GenerateEventLoadToken(event)
|
|
}
|
|
|
|
// LoadHistoryEvent loads a history event from the underlying mutable state using the given token.
|
|
func (m MSPointer) LoadHistoryEvent(ctx Context, token []byte) (*historypb.HistoryEvent, error) {
|
|
return m.backend.LoadHistoryEvent(ctx.goContext(), token)
|
|
}
|
|
|
|
// GetNexusCompletion retrieves the Nexus operation completion data for the given request ID from the underlying mutable state.
|
|
func (m MSPointer) GetNexusCompletion(ctx Context, requestID string) (nexusrpc.CompleteOperationOptions, error) {
|
|
return m.backend.GetNexusCompletion(ctx.goContext(), requestID)
|
|
}
|
|
|
|
// GetWorkflowTypeName retrieves the workflow type name from the underlying mutable state.
|
|
func (m MSPointer) GetWorkflowTypeName() string {
|
|
return m.backend.GetExecutionInfo().GetWorkflowTypeName()
|
|
}
|
|
|
|
// GetNexusUpdateCompletion retrieves the Nexus operation completion data for the given update ID and request ID from the underlying mutable state.
|
|
func (m MSPointer) GetNexusUpdateCompletion(ctx Context, updateID string, requestID string) (nexusrpc.CompleteOperationOptions, error) {
|
|
return m.backend.GetNexusUpdateCompletion(ctx.goContext(), updateID, requestID)
|
|
}
|