Skip to content

Workflow Task stamp - #8103

Merged
stephanos merged 14 commits into
temporalio:mainfrom
stephanos:workflow-task-stamp
Oct 30, 2025
Merged

Workflow Task stamp#8103
stephanos merged 14 commits into
temporalio:mainfrom
stephanos:workflow-task-stamp

Conversation

@stephanos

@stephanos stephanos commented Jul 28, 2025

Copy link
Copy Markdown
Contributor

What changed?

  • added "stamp" field to both workflow execution and transfer/timer workflow task.
  • bumping stamp up when rescheduling a workflow task
  • making sure stamp is current when dequeuing workflow task
  • making sure stamp is current when recoding workflow start

Why?

Activity tasks already have the "stamp" mechanism. This is the same idea for workflow tasks.

It essentially provides a unified approach to invalidate activity and workflow tasks when rescheduling them.

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)

I intend to write more tests for when I'm implementing the update priority feature. It's much easier to setup and test than versioning overrides (which are the only way right now to trigger a stamp increase).

@@ -60,7 +60,3 @@ func (r *ActivityRetryTimerTask) GetType() enumsspb.TaskType {
func (r *ActivityRetryTimerTask) GetStamp() int32 {
return r.Stamp
}

func (r *ActivityRetryTimerTask) SetStamp(stamp int32) {

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.

SetStamp functions aren't used anywhere.

@stephanos
stephanos force-pushed the workflow-task-stamp branch 9 times, most recently from 5f2fc0c to 057109e Compare July 29, 2025 17:21
@@ -5117,8 +5121,6 @@ func (s *mutableStateSuite) TestHasRequestID() {
}

func (s *mutableStateSuite) TestHasRequestID_StateConsistency() {
s.SetupTest()

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.

Not needed.

@stephanos
stephanos force-pushed the workflow-task-stamp branch 2 times, most recently from d317e6f to 23504cf Compare July 29, 2025 17:39
Comment on lines -5015 to -5026
if ms.HasPendingWorkflowTask() && !ms.HasStartedWorkflowTask() &&
// Speculative WFT is directly (without transfer task) added to matching when scheduled.
// It is protected by timeout on both normal and sticky task queues.
// If there is no poller for previous deployment, it will time out,
// and will be rescheduled as normal WFT.
ms.GetPendingWorkflowTask().Type != enumsspb.WORKFLOW_TASK_TYPE_SPECULATIVE {
// Sticky queue was just cleared, so the following call only generates a WorkflowTask, not a WorkflowTaskTimeoutTask.
err := ms.taskGenerator.GenerateScheduleWorkflowTaskTasks(ms.GetPendingWorkflowTask().ScheduledEventID)
if err != nil {
return err
}
}

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.

Migrated into reschedulePendingWorkflowTask.

@stephanos
stephanos force-pushed the workflow-task-stamp branch from 23504cf to 8a6f0dd Compare July 29, 2025 17:52
@@ -17,6 +17,7 @@ type (
TaskQueue string
ScheduledEventID int64
Version int64
Stamp int32

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.

Is my thinking right that only the workflow transfer and timeout task need the stamp?

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.

For workflow pause workstream we might need it in UserTimerTask & StartChildExecutionTask as well. But we are not ready for it yet. So we can add it in the future if needed.

@@ -1056,7 +1059,6 @@ func (s *mutableStateSuite) TestOverride_RedirectFails() {
}

func (s *mutableStateSuite) TestOverride_BaseDeploymentUpdatedOnCompletion() {
s.T().Skip("TODO (Shahab)")

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 test works fine AFAICT.

@stephanos
stephanos force-pushed the workflow-task-stamp branch 2 times, most recently from 878355d to ddbe4ca Compare July 31, 2025 03:02
@stephanos
stephanos marked this pull request as ready for review July 31, 2025 03:02
@stephanos
stephanos requested a review from a team as a code owner July 31, 2025 03:02
@@ -74,6 +73,10 @@ func Invoke(
// - Speculative WFT is lost (ScheduleToStart timeout for speculative WFT will recreate it).
return nil, serviceerror.NewNotFound("Workflow task not found.")
}
if workflowTask.Stamp != mutableState.GetExecutionInfo().GetWorkflowTaskStamp() {
// This happens when the workflow task was rescheduled.
return nil, serviceerrors.NewObsoleteMatchingTask("Workflow task stamp mismatch")

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.

Only place outside of task processing internals where we invalidate a workflow task with an outdated stamp now.

My thinking here is that when deploying a new version, all in-flight tasks and running workflows will have the default stamp, ie zero, and match. Only when the tasks are re-scheduled would they not match.

@stephanos
stephanos force-pushed the workflow-task-stamp branch from 1a5d6bf to f5b73ab Compare August 6, 2025 18:30
@stephanos
stephanos force-pushed the workflow-task-stamp branch 7 times, most recently from 5b6dc75 to 0bec537 Compare September 18, 2025 17:07
@stephanos
stephanos requested a review from gow October 2, 2025 03:54
@stephanos

stephanos commented Oct 2, 2025

Copy link
Copy Markdown
Contributor Author

@gow Alright; check out the 2nd commit I added. There's also a follow-up PR (will be reviewed by matching crew) where I actually use the stamp and have a functional test for it: #8396 (see tests/priority_fairness_test.go).

@stephanos stephanos mentioned this pull request Oct 2, 2025
5 tasks
Comment on lines +237 to +238
// Stamp value from when the workflow task was scheduled. Used to validate the task is still relevant.
int32 stamp = 11;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ideally should have attempt wherever there's stamp. But we can save that for later :)

Comment thread service/history/transfer_queue_standby_task_executor.go
EventID: workflowTask.ScheduledEventID,
ScheduleAttempt: workflowTask.Attempt,
Version: workflowTask.Version,
Stamp: r.mutableState.GetExecutionInfo().GetWorkflowTaskStamp(), // must use current stamp!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

oh maybe provide some more context here. Guess I am still confused on why workflow.Stamp would be wrong here?

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.

Alright; I took another look and when I wrote this I didn't realize that GetWorkflowTaskByID is actually just returning a struct with the current workflow task's info. I thought it returned the currently scheduled workflow task (I didn't know we don't store that). So I've removed the special case here now!

Comment on lines +8257 to +8258
// Reset the attempt; forcing a non-transient workflow task to be scheduled.
ms.executionInfo.Attempt = 1

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we should only do this when Stamp is incremented?

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.

You're right 👍

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We need to make sure the stamp field is replicated properly in state-based replication as well. Please update the syncExecutionInfo() method in this file and have the Stamp field updated.

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.

Oh; that's easy to miss if you don't know where to look! Have we considered some kind of test that verifies a field is either replicated or explicitly ignored?

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.

I'm not sure if I got the test right.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

yeah, I think CGS team is working on some general testing strategy to assert the states are the same on both sides.

) error {
previousEffectiveDeployment := ms.GetEffectiveDeployment()
previousEffectiveVersioningBehavior := ms.GetEffectiveVersioningBehavior()
) (requestReschedulePendingWorkflowTask bool, err error) {

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.

nit: Prefer avoiding named return values in large and complex functions. It hurts readability since return statements are naked and hard to know what values are being returned.

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.

Hm, I 100% agree with that except here because without it, it just says bool and you'll have to scan the whole body to find out what the bool is. Alternatives I can think of are (1) add comment (can get out of date more easily) or (2) adding a var requestReschedulePendingWorkflowTask bool in the body right at the top. WDYT?

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.

Using var now, looks fine 👍

return err
}
// Re-scheduling pending workflow and activity tasks.
err = ms.reschedulePendingWorkflowTask(false)

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 seems like a case where we want to invalidate existing tasks? i.e ms.reschedulePendingWorkflowTask(true)?

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.

So the reason I don't is I cut scope from this PR. The previous code didn't invalidate pending workflow tasks, so there's no behavior change. The recordworkflowtaskstarted API has a dedicated check for buildId.

Why did I declare it out of scope? Yichao asked me how this works with replication and I couldn't tell you since I don't understand the versioning API well enough. So in order to get this merged, I declared it out of scope.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Those versioning rescheduling logic is not working with state-based replication yet. That's something replication crew is aware of and will be fixing them soon. cc @yux0 @xwduan

@stephanos
stephanos requested a review from a team as a code owner October 7, 2025 18:19
@stephanos
stephanos force-pushed the workflow-task-stamp branch 2 times, most recently from 1ec84ce to fc967bf Compare October 7, 2025 18:51
@stephanos
stephanos requested review from gow and yycptt October 7, 2025 21:13

@gow gow left a comment

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.

Looks good to me. Let's wait for @yycptt 's stamp as well.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

yeah, I think CGS team is working on some general testing strategy to assert the states are the same on both sides.

@stephanos
stephanos force-pushed the workflow-task-stamp branch from 826b806 to 741f109 Compare October 30, 2025 00:10
@stephanos
stephanos merged commit 1e3d3af into temporalio:main Oct 30, 2025
57 checks passed
@stephanos
stephanos deleted the workflow-task-stamp branch October 30, 2025 03:27
yiminc pushed a commit that referenced this pull request Dec 2, 2025
## What changed?

Allow updating priority of Workflow and Activity.

Based on

- temporalio/api#610
- #8103

## Why?

Users want to change the priority after starting the workflow/activity.

## How did you test it?
- [ ] built
- [ ] run locally and tested manually
- [ ] covered by existing tests
- [x] added new unit test(s)
- [x] added new functional test(s)
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.

3 participants