Skip to content

Add activity async handoff API definitions - #884

Open
fretz12 wants to merge 6 commits into
mainfrom
fredtzeng/saa-async-completions
Open

fretz12 wants to merge 6 commits into
mainfrom
fredtzeng/saa-async-completions

Conversation

@fretz12

@fretz12 fretz12 commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

What changed?

Added async handoff API definitions for workflow and standalone activities: RespondActivityTaskHandoff, AsyncHandoffOptions, handoff counters and state, timeout types, and namespace capabilities. Added handoff options to workflow scheduling commands and scheduled history events.

Why?

Allow activities to report handoff for external completion, with separate timeout and retry controls before and after handoff. Defines a shared contract for server and SDK implementations while preserving existing behavior when handoff options are absent.

@fretz12
fretz12 marked this pull request as ready for review October 20, 2026 15:25
@fretz12
fretz12 requested review from a team October 20, 2026 15:25
@fretz12
fretz12 force-pushed the fredtzeng/saa-async-completions branch 2 times, most recently from 0777f80 to 68d5430 Compare November 6, 2026 18:43
Comment thread temporal/api/activity/v1/message.proto Outdated
// `ActivityOptions.schedule_to_close_timeout` bounds. Positive heartbeat timeouts are capped by
// their phase timeout and those positive bounds. The server stores and returns normalized values.
// Increasing a bound does not restore a capped value unless that value is also updated.
message AsyncHandoffOptions {

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 don't think the word "async" helps users or adds anything. I'm thinking this should just be "HandoffOptions".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

makes sense

Comment thread temporal/api/activity/v1/message.proto Outdated
google.protobuf.Duration start_delay = 8;

// Two-phase timeout and retry settings.
AsyncHandoffOptions async_handoff_options = 9;

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.

As above, I suggest

Suggested change
AsyncHandoffOptions async_handoff_options = 9;
HandoffOptions handoff_options = 9;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

// aip.dev/not-precedent: "to" is used to indicate interval. --)
google.protobuf.Duration schedule_to_close_timeout = 14;
// Current attempt start -> final result reported timeout
// Configured start-to-close timeout for the activity attempt.

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 believe that SDKs set a local timer based on the returned start_to_close_timeout, so I'm not sure we can change its semantics. If the new PR returns zero here then I think SDKs might start an activity and immediately expire its context unless they all change to handle the new timeouts.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, this requires SDK deadline handling changes. Without handoff options, existing timeout normalization remains unchanged, so we're safe to release this API first while the server feature flag remains disabled. Activities with handoff options set will require a supporting worker SDK that treats zero as disabled. I’ve clarified the behavior in the comment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Comment thread temporal/api/enums/v1/workflow.proto Outdated
// PAUSE_REQUESTED means activity is currently running on the worker, but paused on the server
PENDING_ACTIVITY_STATE_PAUSE_REQUESTED = 5;
// The server has recorded async handoff and is waiting for external completion.
PENDING_ACTIVITY_STATE_AWAITING_COMPLETION = 6;

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’d like to propose that the state name returned by the API is HANDED_OFF. The term “handoff” is used throughout the API (AsyncHandoffOptions, start_to_handoff_timeout, handoff_to_close_timeout, async_handoff_time, handoff_attempt) so it would be consistent to use "handoff" in the state that Describe returns. AWAITING_COMPLETION doesn’t work as well because any activity attempt that’s in progress can be said to be awaiting completion. Sorry I didn’t raise this before now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ok, seems more consistent

@fretz12
fretz12 force-pushed the fredtzeng/saa-async-completions branch from f831c3a to 9c9a951 Compare November 13, 2026 20:12
@fretz12
fretz12 requested a review from dandavison November 13, 2026 21:54
google.protobuf.Timestamp async_handoff_time = 27;

// True while waiting for external completion. Pending pause, cancel, or reset requests do not clear it.
bool awaiting_completion = 28;

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 this one got missed:

Suggested change
bool awaiting_completion = 28;
bool handed_off = 28;

int32 handoff_attempt = 26;

// Most recent durably accepted handoff time. Cleared at the next worker pickup or applied reset.
google.protobuf.Timestamp async_handoff_time = 27;

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.

Suggested change
google.protobuf.Timestamp async_handoff_time = 27;
google.protobuf.Timestamp handoff_time = 27;

// True while the current delivery awaits external completion, independent of
// `ActivityExecutionInfo.run_state`. Cleared when the delivery ends or is reset;
// pending pause, cancel, or reset requests do not clear it.
bool awaiting_completion = 46;

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.

Suggested change
bool awaiting_completion = 46;
bool handed_off = 46;

// Most recent durably recorded handoff time. Retained through retry backoff, waiting for the
// next worker pickup, and terminal closure. Cleared when a reset is applied or the next delivery
// starts on a worker.
google.protobuf.Timestamp async_handoff_time = 45;

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.

Suggested change
google.protobuf.Timestamp async_handoff_time = 45;
google.protobuf.Timestamp handoff_time = 45;

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