Skip to content

Conversation

@fretz12
Copy link
Contributor

@fretz12 fretz12 commented Nov 16, 2025

What changed?

Added standalone activity completion and failure handling. Refactored existing timeout failure handling. Refactored existing check for retry method.

Why?

Needed to support standalone activities full operation.

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)

@fretz12 fretz12 requested a review from Copilot November 16, 2025 17:07
@fretz12 fretz12 requested review from a team as code owners November 16, 2025 17:07
@fretz12 fretz12 changed the title Saa complete activity Add standalone activity completion and failure support Nov 16, 2025
Copilot finished reviewing on behalf of fretz12 November 16, 2025 17:10
@fretz12 fretz12 marked this pull request as draft November 16, 2025 17:11
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This pull request adds standalone activity completion and failure handling functionality to the codebase. It refactors existing timeout failure handling and consolidates retry logic into a common failure module.

  • Added handling for standalone activity completion and failure via RespondActivityTaskCompleted and RespondActivityTaskFailed APIs
  • Refactored retry checking logic from service/history/workflow/retry.go into a shared common/failure package
  • Extended task tokens to include component references for standalone activities

Reviewed Changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/standalone_activity_test.go Added comprehensive tests for standalone activity completion and failure scenarios
service/matching/matching_engine.go Fixed buildId naming convention and removed unnecessary blank line
service/history/workflow/retry_test.go Updated tests to use the new common failure.IsRetryable function
service/history/workflow/retry.go Removed local isRetryable function in favor of common/failure package
service/history/workflow/mutable_state_impl.go Updated to use failure.IsRetryable from common package
service/history/history_engine_test.go Improved test assertions using Len and Empty helpers
service/history/handler.go Updated task token validation to support both workflow and standalone activities
service/history/chasm_engine.go Fixed reference to use requestRef.NamespaceID instead of nested EntityKey
service/history/api/respondworkflowtaskcompleted/workflow_task_completed_handler.go Added nil component ref parameter to task token creation
service/history/api/respondactivitytaskfailed/api.go Added standalone activity failure handling via component ref
service/history/api/respondactivitytaskcompleted/api.go Added standalone activity completion handling via component ref
service/history/api/recordactivitytaskstarted/api.go Renamed function to follow Go naming convention for ID
service/frontend/workflow_handler.go Added component ref handling for standalone activity completion/failure by ID
proto/internal/temporal/server/api/token/v1/message.proto Added component_ref field to Task message
common/tasktoken/token.go Added componentRef parameter to NewActivityTaskToken
common/searchattribute/encode_test.go Improved test assertions using assert.Empty
common/persistence/visibility/store/sql/query_converter_test.go Simplified string formatting
common/persistence/visibility/store/query/interceptors_test.go Changed assertions to use JSONEq for better comparison
common/persistence/visibility/store/elasticsearch/visibility_store_read_test.go Changed assertion to use JSONEq for JSON comparison
common/failure/failure.go Added IsRetryable function for shared retry logic
chasm/lib/activity/statemachine_test.go Added tests for TransitionCompleted and TransitionFailed
chasm/lib/activity/statemachine.go Refactored transition handling to use failure parameter and added completion/failure logic
chasm/lib/activity/activity_tasks.go Updated to pass failure parameter to TransitionRescheduled
chasm/lib/activity/activity.go Added RecordActivityCompleted and HandleActivityFailed methods with retry logic
api/token/v1/message.pb.go Generated code for component_ref field

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Member

@bergundy bergundy left a comment

Choose a reason for hiding this comment

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

I didn't go over everything but generally this LGTM.

@fretz12 fretz12 marked this pull request as ready for review November 19, 2025 23:27
Copilot finished reviewing on behalf of fretz12 November 19, 2025 23:30
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

errWorkflowExecutionNotSet = serviceerror.NewInvalidArgument("WorkflowExecution not set on request.")
errTaskQueueNotSet = serviceerror.NewInvalidArgument("Task queue not set.")
errWorkflowIDNotSet = serviceerror.NewInvalidArgument("WorkflowId is not set on request.")
errBusinessIDNotSet = serviceerror.NewInvalidArgument("Business ID is not set on request.")
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

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

The error message "Business ID is not set on request." is unclear and potentially confusing. Since this is checking for either ComponentRef or WorkflowId (as seen in validateTaskToken), a more descriptive message would be "WorkflowId or ComponentRef must be set on request." to better indicate what is expected.

Suggested change
errBusinessIDNotSet = serviceerror.NewInvalidArgument("Business ID is not set on request.")
errBusinessIDNotSet = serviceerror.NewInvalidArgument("WorkflowId or ComponentRef must be set on request.")

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

This should be an internal error IMHO, if it happens it's because the frontend has a bug. But let's not change the semantics here without a broader discussion.

}),
Outcome: chasm.NewDataField(ctx, &activitypb.ActivityOutcome{}),
Visibility: chasm.NewComponentField(ctx, visibility),
LastHeartbeat: chasm.NewDataField(ctx, &activitypb.ActivityHeartbeatState{}),
Copy link
Member

Choose a reason for hiding this comment

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

IIUC, if you don't create this component by default, it will reduce load on the DB by not creating the cell for this node. @yycptt correct me if I'm wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah nice optimization. I've made a helper method that will get and create it lazily.
cc: @dandavison

Comment on lines +97 to +91
startResp := s.startAndValidateActivity(ctx, t, activityID, taskQueue)
runID := startResp.RunId

pollTaskResp := s.pollActivityTaskAndValidate(ctx, t, activityID, taskQueue, runID)

_, err := s.FrontendClient().RespondActivityTaskCompleted(ctx, &workflowservice.RespondActivityTaskCompletedRequest{
Namespace: s.Namespace().String(),
TaskToken: pollTaskResp.TaskToken,
Result: defaultResult,
Identity: "new-worker",
})
require.NoError(t, err)

s.validateCompletion(ctx, t, activityID, runID, "new-worker")
Copy link
Member

Choose a reason for hiding this comment

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

I am not a fan of these test helpers that hide a lot of the logic and make it hard to follow exactly what is happening. Personally, I am on team repeat yourself in tests.
I developed this notion independently and finally took a stronger stance after watching https://www.youtube.com/watch?v=8hQG7QlcLBk.

That being said, I don't think everyone shares this stance, and I don't think it would be fair to block the PR because tests aren't written in this specific style.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see the point and thanks for sharing the vid. I think there's a balance between the two.
"Limit helpers to very reused logic that doesn't fail often or fails all at once" - I like that philosophy.
Let me run by the team in the next standup than we can lock it down.

@fretz12 fretz12 requested a review from bergundy November 21, 2025 18:53
@dandavison dandavison force-pushed the poll-component branch 2 times, most recently from 863d5bf to ee79ea9 Compare November 23, 2025 18:30
@dandavison dandavison force-pushed the poll-component branch 5 times, most recently from cd288dc to e9a1223 Compare November 25, 2025 01:51
@fretz12 fretz12 requested a review from bergundy November 25, 2025 05:16
@dandavison dandavison force-pushed the poll-component branch 3 times, most recently from 957b571 to e4dd35d Compare November 25, 2025 22:58
Copy link
Member

@bergundy bergundy left a comment

Choose a reason for hiding this comment

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

I'm still seeing changes related to @dandavison's PollComponent implementation but I trust that the two of you will iron things out. I didn't have any more blocking comments.


type ActivityStore interface {
// PopulateRecordActivityTaskStartedResponse populates the response for RecordActivityTaskStarted
PopulateRecordActivityTaskStartedResponse(ctx chasm.Context, key chasm.EntityKey, response *historyservice.RecordActivityTaskStartedResponse) error
Copy link
Member

Choose a reason for hiding this comment

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

Not blocking but you will want Activity in both of these method names because when the workflow component implements these APIs it will be important to qualify.
Don't worry about this though, we are going to want to rewrite all of this eventually anyways.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Noted.

StartToCloseTimeout: durationpb.New(defaultStartToCloseTimeout),
Status: activitypb.ACTIVITY_EXECUTION_STATUS_STARTED,
},
Attempt: chasm.NewDataField(ctx, attemptState),
Copy link
Member

Choose a reason for hiding this comment

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

This field should be called LastAttempt IMHO.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I feel it is implicitly understood in the way it's used here as there's only a single attemptstate here and attemptstate is not used in any other way elsewhere. So, unless you feel strongly about it I'd prefer to keep it simple as Attempt.

@fretz12 fretz12 force-pushed the saa-complete-activity branch from afa9058 to d19eee6 Compare November 26, 2025 00:00
@fretz12 fretz12 requested a review from bergundy November 26, 2025 01:55
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.

4 participants