Skip to content

Retry transient errors in ActivityCompletionClient.heartbeat - #2985

Open
arimu1 wants to merge 1 commit into
temporalio:mainfrom
arimu1:fix/2984-heartbeat-retry-transient
Open

Retry transient errors in ActivityCompletionClient.heartbeat#2985
arimu1 wants to merge 1 commit into
temporalio:mainfrom
arimu1:fix/2984-heartbeat-retry-transient

Conversation

@arimu1

@arimu1 arimu1 commented Jul 31, 2026

Copy link
Copy Markdown

What changed?

ManualActivityCompletionClientImpl.recordHeartbeat now wraps the heartbeat RPC in grpcRetryer.retryWithResult(...) with the same replyGrpcRetryerOptions used by complete, fail, and reportCancellation.

Unit tests cover:

  • retry of RESOURCE_EXHAUSTED / UNAVAILABLE until success (task-token and by-id paths)
  • no retry of non-retryable NOT_FOUND
  • cancel-requested response still throws ActivityCanceledException
  • exhaustion of retries surfaces ActivityCompletionFailureException

Also rethrow ActivityCompletionException so cancel/reset/paused signals are not wrapped as ActivityCompletionFailureException by the outer catch.

Why?

Async completion clients hold the task token outside the worker. A single transient server error (most often namespace rate limiting via RESOURCE_EXHAUSTED, also UNAVAILABLE / DEADLINE_EXCEEDED) on heartbeat could fail the call immediately and risk activity heartbeat timeout. The other three reply RPCs already retry; heartbeat was the only exception.

Breaking changes?

No intentional public API changes. Callers that previously observed cancel/reset/paused as ActivityCompletionFailureException wrapping the more specific type will now see the specific exception directly (ActivityCanceledException, ActivityResetException, ActivityPausedException).

Server PR

N/A

Fixes #2984

Checklist

  1. All tests passed for relevant packages
  2. User-facing docs / error handling for cancel path checked
  3. Unit tests added for retry behavior

…eartbeat

recordHeartbeat was the only reply path that did not use GrpcRetryer, so a
single RESOURCE_EXHAUSTED/UNAVAILABLE could fail an async activity heartbeat.
Wrap the RPC with the same replyGrpcRetryerOptions used by complete, fail,
and reportCancellation. Also rethrow ActivityCompletionException so cancel/
reset/paused signals are not wrapped as ActivityCompletionFailureException.

Fixes temporalio#2984
@arimu1
arimu1 requested a review from a team as a code owner July 31, 2026 16:17
@CLAassistant

CLAassistant commented Jul 31, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

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.

Retry transient errors in ActivityCompletionClient.heartbeat

2 participants