@@ -15,6 +15,7 @@ import (
1515 "go.temporal.io/server/chasm"
1616 nexusoperationpb "go.temporal.io/server/chasm/lib/nexusoperation/gen/nexusoperationpb/v1"
1717 "go.temporal.io/server/common/backoff"
18+ "go.temporal.io/server/common/softassert"
1819 queueserrors "go.temporal.io/server/service/history/queues/errors"
1920 "google.golang.org/protobuf/types/known/durationpb"
2021 "google.golang.org/protobuf/types/known/timestamppb"
@@ -74,6 +75,7 @@ func newStandaloneOperation(
7475) (* Operation , error ) {
7576 frontendReq := req .GetFrontendRequest ()
7677 op := NewOperation (& nexusoperationpb.OperationState {
78+ EndpointId : req .GetEndpointId (),
7779 Endpoint : frontendReq .GetEndpoint (),
7880 Service : frontendReq .GetService (),
7981 Operation : frontendReq .GetOperation (),
@@ -156,41 +158,29 @@ func (o *Operation) onStarted(ctx chasm.MutableContext, operationToken string, l
156158 if store , ok := o .Store .TryGet (ctx ); ok {
157159 return store .OnNexusOperationStarted (ctx , o , operationToken , links )
158160 }
161+ o .Links = append (o .Links , links ... )
159162 return TransitionStarted .Apply (o , ctx , EventStarted {OperationToken : operationToken })
160163}
161164
162165func (o * Operation ) onCompleted (ctx chasm.MutableContext , result * commonpb.Payload , links []* commonpb.Link ) error {
163166 if store , ok := o .Store .TryGet (ctx ); ok {
164167 return store .OnNexusOperationCompleted (ctx , o , result , links )
165168 }
166- outcome := o .outcome (ctx )
167- outcome .Variant = & nexusoperationpb.OperationOutcome_Successful_ {
168- Successful : & nexusoperationpb.OperationOutcome_Successful {Result : result },
169- }
170- return TransitionSucceeded .Apply (o , ctx , EventSucceeded {})
169+ o .Links = append (o .Links , links ... )
170+ return TransitionSucceeded .Apply (o , ctx , EventSucceeded {Result : result })
171171}
172172
173173func (o * Operation ) onFailed (ctx chasm.MutableContext , cause * failurepb.Failure ) error {
174174 if store , ok := o .Store .TryGet (ctx ); ok {
175175 return store .OnNexusOperationFailed (ctx , o , cause )
176176 }
177- if cause != nil {
178- o .outcome (ctx ).Variant = & nexusoperationpb.OperationOutcome_Failed_ {
179- Failed : & nexusoperationpb.OperationOutcome_Failed {Failure : cause },
180- }
181- }
182177 return TransitionFailed .Apply (o , ctx , EventFailed {Failure : cause })
183178}
184179
185180func (o * Operation ) onCanceled (ctx chasm.MutableContext , cause * failurepb.Failure ) error {
186181 if store , ok := o .Store .TryGet (ctx ); ok {
187182 return store .OnNexusOperationCanceled (ctx , o , cause )
188183 }
189- if cause != nil {
190- o .outcome (ctx ).Variant = & nexusoperationpb.OperationOutcome_Failed_ {
191- Failed : & nexusoperationpb.OperationOutcome_Failed {Failure : cause },
192- }
193- }
194184 return TransitionCanceled .Apply (o , ctx , EventCanceled {Failure : cause })
195185}
196186
@@ -389,14 +379,25 @@ func (o *Operation) buildPollResponse(
389379}
390380
391381func (o * Operation ) describeOutcome (ctx chasm.Context ) (* commonpb.Payload , * failurepb.Failure ) {
392- outcome := o .Outcome .Get (ctx )
393- if successful := outcome .GetSuccessful (); successful != nil {
394- return successful .GetResult (), nil
395- }
396- if failure := outcome .GetFailed ().GetFailure (); failure != nil {
397- return nil , failure
382+ outcome , hasOutcome := o .Outcome .TryGet (ctx )
383+
384+ switch {
385+ case ! hasOutcome :
386+ return nil , o .LastAttemptFailure
387+ case outcome .GetSuccessful () != nil :
388+ return outcome .GetSuccessful ().GetResult (), nil
389+ case outcome .GetFailed () != nil :
390+ // Timeouts often close after one or more retryable attempt failures. For describe/poll, prefer the
391+ // last concrete attempt failure over the generic timeout wrapper because it is more actionable.
392+ // Note that LastAttemptFailure may be nil if the operation timed out before any attempt.
393+ if o .Status == nexusoperationpb .OPERATION_STATUS_TIMED_OUT && o .LastAttemptFailure != nil {
394+ return nil , o .LastAttemptFailure
395+ }
396+ return nil , outcome .GetFailed ().GetFailure ()
397+ default :
398+ softassert .Fail (ctx .Logger (), "operation outcome has no variant set" )
399+ return nil , nil
398400 }
399- return nil , o .LastAttemptFailure
400401}
401402
402403func (o * Operation ) isWaitStageReached (_ chasm.Context , waitStage enumspb.NexusOperationWaitStage ) bool {
@@ -441,6 +442,7 @@ func (o *Operation) buildExecutionInfo(ctx chasm.Context) *nexuspb.NexusOperatio
441442 },
442443 NexusHeader : requestData .GetNexusHeader (),
443444 UserMetadata : requestData .GetUserMetadata (),
445+ Links : o .Links ,
444446 Identity : requestData .GetIdentity (),
445447 }
446448
0 commit comments