Skip to content

Add activity outcome in start activity response#10359

Draft
ks-temporal wants to merge 3 commits into
temporalio:mainfrom
ks-temporal:ks/ACT-919-activity-outcome
Draft

Add activity outcome in start activity response#10359
ks-temporal wants to merge 3 commits into
temporalio:mainfrom
ks-temporal:ks/ACT-919-activity-outcome

Conversation

@ks-temporal
Copy link
Copy Markdown

What changed?

In StartActivityExecution if IncludeOutcome is set in the request and the
activity is already started, and the outcome is available, then instead of
returning AlreadyStarted error, return success with the outcome and runID
of the already started activity.

If the caller desires, it can set the IncludeOutcome in the request, and
the server will return the outcome when the reuse policy is set
to AllowDuplicateFailedOnly and the previous run succeeded,
or when set to RejectDuplicate and the previous run completed.

Before adding the completion callbacks, do the same check, and avoid
adding callbacks on completed activity, as it will fail, but return success
with outcome of the completed activity. Refactor the check-and-add to
a new Activity function to allow unit test.

Why?

So that the outcome is included in response to StartActivityExecution
if the execution is already started, and the activity is already completed,
to avoid another query for the outcome.

When a caller's StartActivityExecution short-circuits to an existing run
with the same activity ID because of an ID reuse or conflict policy, the
caller often wants the outcome of the existing run, not just the identifier
or an error pointing at it. Retrieving the outcome in the response avoids
the caller to use a second RPC of DescribeActivityExecution to retrieve
a result that the server already has cached.

The activity outcome is embedded in a success response rather than
within an error, which otherwise would have happened without the
include_outcome request flag.

How did you test it?

  • built
  • run locally and tested manually
  • covered by existing tests
  • added new unit test(s)
  • added new functional test(s)

In StartActivityExecution if IncludeOutcome is set in the request
and the activity is already started, and the outcome is available,
then instead of returning AlreadyStarted error, return success
with the outcome and runID of the already started activity.

Before adding completion callbacks, do the same check, and
avoid adding callbacks on completed activity, as it will fail,
but return success with outcome of the completed activity.
Refactor the check and add to Activity function to allow
unit test.
@ks-temporal ks-temporal changed the title Ks/act 919 activity outcome Add activity outcome in start activity response May 22, 2026
Comment thread chasm/lib/activity/handler.go Outdated
Comment thread chasm/lib/activity/handler.go Outdated
Comment thread chasm/lib/activity/handler.go
Comment on lines +303 to +317
func (a *Activity) getOutcomeOrAddCallbacks(
ctx chasm.MutableContext, input getOutcomeOrAddCallbacksInput,
) (*apiactivitypb.ActivityExecutionOutcome, error) {
var outcome *apiactivitypb.ActivityExecutionOutcome

if input.includeOutcome {
outcome = a.outcome(ctx)
}
// Do not add completion callbacks if activity already completed.
if outcome != nil {
return outcome, nil
}

return nil, a.addCompletionCallbacks(ctx, input.requestID, input.callbacks, input.maxCallbacks)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can simplify

Suggested change
func (a *Activity) getOutcomeOrAddCallbacks(
ctx chasm.MutableContext, input getOutcomeOrAddCallbacksInput,
) (*apiactivitypb.ActivityExecutionOutcome, error) {
var outcome *apiactivitypb.ActivityExecutionOutcome
if input.includeOutcome {
outcome = a.outcome(ctx)
}
// Do not add completion callbacks if activity already completed.
if outcome != nil {
return outcome, nil
}
return nil, a.addCompletionCallbacks(ctx, input.requestID, input.callbacks, input.maxCallbacks)
}
func (a *Activity) getOutcomeOrAddCallbacks(
ctx chasm.MutableContext, input getOutcomeOrAddCallbacksInput,
) (*apiactivitypb.ActivityExecutionOutcome, error) {
if input.includeOutcome && a.LifecycleState(ctx).IsClosed() {
return a.outcome(ctx), nil
}
return nil, a.addCompletionCallbacks(ctx, input.requestID, input.callbacks, input.maxCallbacks)
}

Simplified getOutcomeOrAddCallback by checking if activity state
is closed, instead of presence of outcome.

Refactor handling of AlreadyStartedErr in separate function.

Return error from ReadComponent instead of AlreadyStartedErr if
ReadComponent fails.

Return immediately if error is present but is not AlreadyStartedErr.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants