Skip to content

Drop reset_attempts and reset_heartbeat from UnpauseActivityExecution - #11393

Merged
dandavison merged 2 commits into
mainfrom
simplify-activity-unpause-wfa
Aug 3, 2026
Merged

Drop reset_attempts and reset_heartbeat from UnpauseActivityExecution#11393
dandavison merged 2 commits into
mainfrom
simplify-activity-unpause-wfa

Conversation

@dandavison

@dandavison dandavison commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

See API change temporalio/api#846

What changed?

  • Drop reset_attempts and reset_heartbeat from UnpauseActivityExecution

Why?

  • We have so far been unable to assign desirable and consistent semantics to them during implementation: for example if Unpause[resetAttempts] is received during retry backoff it is unclear whether to honor the remaining delay time, because this is how Unpause usually behaves, or dispatch immediately, because this is how Reset behaves.
  • No known user demand
  • They are confusing: they mix Unpause and Reset functionality in a confusing way
  • They can be added later

How did you test it?

  • covered by existing tests

Breaking changes

  • This API has always been rejected by the server. When server starts to accept it, an old client could submit these options and they would be ignored. Operator API is not GA.

Note

Medium Risk
Changes activity unpause scheduling semantics for the execution API and drops reset-on-unpause behavior that was only partially implemented; low user impact if the API was not GA and had no known callers.

Overview
Aligns the server with the UnpauseActivityExecution API change: reset_attempts and reset_heartbeat are no longer part of unpause for standalone (CHASM) activities.

CHASM activity unpause no longer resets attempt count, retry interval, or heartbeat state on unpause, and always considers the pending retry backoff when scheduling dispatch (the branch that skipped that when reset_attempts was set is removed). Workflow-embedded unpause forwarding via UnpauseActivityExecution no longer passes those fields to the legacy UnpauseActivity history call (jitter and identity only).

go.temporal.io/api is bumped to the revision that removes the fields from UnpauseActivityExecutionRequest.

Tests are updated so unpause helpers no longer take a reset flag; reset-on-unpause coverage stays on legacy UnpauseActivity only (execution API skips that case). Standalone tests for UnpauseWithResetAttempts and UnpauseWithResetHeartbeat on UnpauseActivityExecution are removed.

Reviewed by Cursor Bugbot for commit 7a41d50. Bugbot is set up for automated code reviews on this repo. Configure here.

@dandavison dandavison closed this Aug 3, 2026
@dandavison dandavison reopened this Aug 3, 2026
@dandavison
dandavison marked this pull request as ready for review August 3, 2026 18:50
@dandavison
dandavison requested a review from a team August 3, 2026 18:50
@dandavison
dandavison requested review from a team as code owners August 3, 2026 18:50
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Claude finished @dandavison's task in 4m 49s —— View job


Review complete

  • Read the repo review guidelines (.claude/skills/review.github/copilot-instructions.md)
  • Read the diff (chasm/lib/activity, tests/, go.mod)
  • Checked for stale references to the removed fields
  • Checked that the deleted tests' coverage is retained elsewhere
  • Posted findings as inline comments

Two inline comments, both non-blocking: one on the test-table shape in tests/activity_api_pause_test.go, one asking whether the workflow-vs-standalone divergence in unpause retry-backoff timing is intended now that reset_attempts is gone.

What I verified:

  • No remaining references to ResetAttempts/ResetHeartbeat on the new request types. The surviving hits are all the deprecated UnpauseActivity/ResetActivity path (batcher, service/history/api/unpauseactivity, ResetHeartbeats on persisted ActivityInfo), which keep their flags. chasm/lib/activity/validator.go, statemachine.go, and the driver helpers in tests/ needed no changes and have none.
  • The deleted standalone tests are not a coverage loss. UnpauseWithResetAttempts covered a path that no longer exists, and the retained behavior is asserted by PauseWhileRetryHonorsBackoff and PauseWhileRetryBackoffSurvivesOptionsUpdateAfterUnpause. Heartbeat clearing on reset is still covered by ResetClearsHeartbeatDetails / ResetClearsHeartbeatState, and attempt restart through the new API by TestActivityApiResetClientTestSuite (which runs against both ResetActivity and ResetActivityExecution).
  • unpauseDispatchTime and unpause read correctly after the deletions — no dead locals, event is still needed for jitter.

Not done: I could not compile or run tests in this environment (go build was not permitted), so I did not verify that the go.temporal.io/api bump actually removes the two fields — CI covers that.
· branch simplify-activity-unpause-wfa

Unpause resumes an activity; it should not also mutate the attempt
counter or discard the heartbeat checkpoint. An operator wanting either
would look for it on Reset, which offers both. Ship the simple API
first.

Picks up temporalio/api-go simplify-activity-unpause, which removes the
two fields from UnpauseActivityExecutionRequest. The deprecated
UnpauseActivity keeps them, so TestActivityPauseApi_WithReset now runs
only against that API.

Removing the reset_attempts branch also fixes a defect it carried:
unpauseDispatchTime skipped dispatchTimeForRetry when the flag was set,
so an operator could defeat a retry backoff by pausing and unpausing.

go build ./... && go vet -tags test_dep ./... && go test ./chasm/lib/activity/...

Extend the unpause simplification to the workflow-activity API

Drops reset_attempts and reset_heartbeat from the deprecated
UnpauseActivity and from the unpause batch operation, so unpause means
the same thing on every surface: it resumes an activity, and Reset is
the operation that restarts it as if on its first attempt.

workflow.UnpauseActivity loses both parameters with them.
TestActivityPauseApi_WithReset goes too: no unpause API can restart
attempts now, so the case it covered no longer exists.

ActivityInfo.reset_heartbeats stays: it is written by the Reset path,
which keeps its own reset_heartbeat flag.

go build ./... && go vet -tags test_dep ./... && go test ./chasm/lib/activity/... ./service/history/api/unpauseactivity/... ./service/worker/batcher/...

Revert "Extend the unpause simplification to the workflow-activity API"

This reverts commit 8295082.

update api commit
@dandavison
dandavison force-pushed the simplify-activity-unpause-wfa branch from d7eec33 to eb47bd7 Compare August 3, 2026 18:54
Comment on lines 39 to +42
pause func(ctx context.Context, s *testcore.TestEnv, wfID, actID, identity, reason, requestID string) error
unpause func(ctx context.Context, s *testcore.TestEnv, wfID, actID, identity string, resetAttempts bool) error
unpause func(ctx context.Context, s *testcore.TestEnv, wfID, actID, identity string) error
// unpauseResettingAttempts is nil on an API with no reset_attempts flag. Only the deprecated
// UnpauseActivity has one; UnpauseActivityExecution deliberately does not.

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.

Now that only one of the two APIs supports reset_attempts, the table gains a second func field, a nil check, a t.Skip, and a comment — all to express "this subtest only applies to the legacy API". Hoisting TestActivityPauseApi_WithReset out of the for _, api := range pauseAPIs() loop and having it call PauseActivity/UnpauseActivity directly would delete all four. The subtest body already builds its own env, workflow func and activity func; the only things it takes from api are pause and the unpause adapter, so nothing is shared that would need to be duplicated.

That also avoids the slightly odd shape where a subtest inside the UnpauseActivityExecution group exists only to be skipped.

Minor, on the comment itself: deliberately does not refers to the decision rather than the behavior. If you keep the field, something like // unpauseResettingAttempts is nil for APIs without a reset_attempts flag on unpause. says the same thing without it.

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.

Declined. That would cause a large diff to the WFA test, and this PR is about SAA not WFA.

Comment on lines +425 to +427
Activity: &workflowservice.UnpauseActivityRequest_Id{Id: frontendReq.GetActivityId()},
Jitter: frontendReq.GetJitter(),
Identity: frontendReq.GetIdentity(),

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.

Not introduced here, but this change makes it the whole story for the API, so worth confirming it's intended: the two backends of UnpauseActivityExecution now disagree on retry-backoff timing.

  • Workflow activity (this branch): workflow.UnpauseActivity regenerates the retry task at now(+jitter) whenever the activity is SCHEDULED (service/history/workflow/activity.go:401-410), independent of the reset flags — so unpause drops the remaining backoff and dispatches immediately.
  • Standalone activity: unpauseDispatchTime now always consults dispatchTimeForRetry, so unpause waits out the remaining backoff. tests/activity_standalone_test.go:11095 asserts exactly that ("unpause must honor the remaining retry backoff").

Concretely: pause an activity sitting in a 30s retry backoff, then unpause. A workflow activity runs right away; a standalone activity waits for the original retry deadline. Previously reset_attempts=true gave the standalone path the workflow path's timing; with the flag gone, the only way to skip the backoff on a standalone activity is ResetActivityExecution, which also resets the attempt count and clears heartbeat details.

If the intent is that unpause is purely "resume", the legacy workflow path is the odd one out and may deserve a follow-up issue.

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.

This is something to fix in the workflow activity parity drive post saa release

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.

This is intended: we will bring WFA into parity with SAA later. Neither have this API at GA.

@dandavison dandavison added the reliability-2026 Reliability related changes label Aug 3, 2026
Comment on lines +425 to +427
Activity: &workflowservice.UnpauseActivityRequest_Id{Id: frontendReq.GetActivityId()},
Jitter: frontendReq.GetJitter(),
Identity: frontendReq.GetIdentity(),

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.

This is something to fix in the workflow activity parity drive post saa release

@dandavison
dandavison merged commit c92b3d3 into main Aug 3, 2026
52 checks passed
@dandavison
dandavison deleted the simplify-activity-unpause-wfa branch August 3, 2026 21:17
dandavison added a commit that referenced this pull request Aug 3, 2026
main dropped reset_heartbeat from UnpauseActivityExecution (#11393), so the
UnpauseWithResetHeartbeat test goes away; keep this branch's
UnpauseWhileCancelRequestedFails rename and FailedPrecondition assertions.

go test ./tests/ -run TestActivityStandaloneSuite
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

reliability-2026 Reliability related changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants