Skip to content

Propagate backlinks on Signal and Signal-with-Start responses#9897

Open
long-nt-tran wants to merge 2 commits intotemporalio:mainfrom
long-nt-tran:signals-updates-backlink
Open

Propagate backlinks on Signal and Signal-with-Start responses#9897
long-nt-tran wants to merge 2 commits intotemporalio:mainfrom
long-nt-tran:signals-updates-backlink

Conversation

@long-nt-tran
Copy link
Copy Markdown
Contributor

@long-nt-tran long-nt-tran commented Apr 9, 2026

What changed?

High level

With temporalio/api#761 to add the linking on the Signal and Signal-with-Start responses, This PR adds logic from the server that:

  • Attaches requestID from Signal and Signal-with-Start requests to the mutable state + event store so these requestIDs stay in buffer
  • Return a backlink in the response that references the requestID
  • On buffer flush to the DB transaction, attach these requestID to a concrete eventID, which would allow users to later know which event correlated w/ this request

Important note: request ID mapping to multiple events

Additionally, because a Signal-with-Start already attaches a requestID onto the EVENT_TYPE_WORKFLOW_EXECUTION_STARTED event, after offline discussion w/ @bergundy and @Quinn-With-Two-Ns, we decided to augment RequestIDInfo struct with a slice of events_metadata to map to a request ID to multiple events. For compatibility, serde logic still have to populate both -- can be deleted in a future PR once everything is upgraded.

Everywhere else in code, I shifted to extract / populate the events_metadata when attaching a request ID to an event. The interesting change is in service/history/api/describeworkflow/api.go, where we will return the EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED event if there are multiple events mapping to a request ID -- that's because Signal-with-Start is the only request ID where there could be multiple events mapping to that request ID nowadays.

Why?

This will enable the caller of the signal to have a backlink to the cross-namespace signal invoked, which will become more relevant for Nexus SDK ergonomics.

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)

In functional tests, I augmented existing tests for Signal and Signal-with-Start to:

  • Ensure that backlink is returned via the responses
  • Later use DescribeWorkflow to ensure that we get a concrete EventID (mapped when buffer flushed)
  • Multiple signals with the same requestID gets de-duped
$ go test ./tests/ -run TestLinksTestSuite
ok      go.temporal.io/server/tests     1.486s
$ go test ./tests/ -run 'TestNexusWorkflowTestSuite' -count=1
ok      go.temporal.io/server/tests     4.714s

Potential risks

Need to test end-to-end to see that the link shows up correctly in the Web UI.

Comment thread service/history/api/link_util.go Outdated
@long-nt-tran long-nt-tran force-pushed the signals-updates-backlink branch 3 times, most recently from 589224e to 4c69cc2 Compare April 10, 2026 16:22
Comment thread go.mod Outdated
@long-nt-tran long-nt-tran marked this pull request as ready for review April 10, 2026 16:48
@long-nt-tran long-nt-tran requested review from a team as code owners April 10, 2026 16:48
Copy link
Copy Markdown
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.

Here's what's missing:

  • Adding to the map that tracks request ID to event ID
  • A functional test that verifies that request IDs for all of these requests are added to the map
  • Ensure that the workflow start link is only populated if an execution was started

Comment thread service/history/api/signalwithstartworkflow/api_test.go Outdated
Comment thread service/history/api/signalworkflow/api_test.go
@long-nt-tran long-nt-tran force-pushed the signals-updates-backlink branch 5 times, most recently from 51b9594 to 52c0da3 Compare April 13, 2026 20:21
Comment thread go.mod Outdated
@long-nt-tran
Copy link
Copy Markdown
Contributor Author

Addressed feedback, I think the cleanest way to have the requestID be in the mutable state is to have it on the event is to have it be a new field in WorkflowExecutionSignaledEventAttributes, so I did need to add this field to the api PR. Let me know if there are other preferable alternatives -- I saw some other events also do the same thing of having requestID be part of the attributes so followed that pattern.

Also put all testing at functional test level so we can end-to-end assert on request ID presence + concrete event ID resolution -- edited summary to reflect this.

cc @bergundy @Quinn-With-Two-Ns

@long-nt-tran long-nt-tran requested a review from bergundy April 13, 2026 20:48
@bergundy
Copy link
Copy Markdown
Member

Addressed feedback, I think the cleanest way to have the requestID be in the mutable state is to have it on the event is to have it be a new field in WorkflowExecutionSignaledEventAttributes, so I did need to add this field to the api PR. Let me know if there are other preferable alternatives -- I saw some other events also do the same thing of having requestID be part of the attributes so followed that pattern.

Also put all testing at functional test level so we can end-to-end assert on request ID presence + concrete event ID resolution -- edited summary to reflect this.

cc @bergundy @Quinn-With-Two-Ns

That makes sense to me because the signal could be cherry picked into a new history branch on conflict resolution and reset and you'll want to carry over the same request ID when that happens.

Comment thread service/history/api/multioperation/api.go Outdated
Comment thread service/history/ndc/workflow_resetter.go Outdated
Comment on lines +5674 to +5676
if requestID != "" {
ms.AttachRequestID(requestID, enumspb.EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED, common.BufferedEventID)
}
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.

Not quite seeing the value of attaching the buffered event ID here. It's supposed to be a temporary ID.
Also not quite sure how the request ID mapping works with signal-with-start where the same request ID maps to two history events. We shouldn't override the request ID of the WorkflowExecutionStarted event.

I think we may need to extend the proto to allow a single request ID to reference two separate events.

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.

captured offline discussion in summary -- mapping request ID to multiple events. Will get review from foundation as well before merging

long-nt-tran added a commit to temporalio/api that referenced this pull request Apr 14, 2026
…responses (#761)

<!-- Describe what has changed in this PR -->
**What changed?**

Added `link` fields on `SignalWorkflowExecutionResponse` and
`SignalWithStartWorkflowExecutionRequest`. I think a singular link
should suffice but if reviewers feel otherwise (especially w.r.t.
`SignalWithStartWorkflowExecutionRequest`) let me know.

<!-- Tell your future self why have you made these changes -->
**Why?**

To propagate backlinks on signal and signal-with-start executions back
to the caller.


<!-- Are there any breaking changes on binary or code level? -->
**Breaking changes**

Not a breaking change (unused field)


<!-- If this breaks the Server, please provide the Server PR to merge
right after this PR was merged. -->
**Server PR**

temporalio/temporal#9897
temporal-cicd bot pushed a commit to temporalio/api-go that referenced this pull request Apr 14, 2026
…responses (#761)

<!-- Describe what has changed in this PR -->
**What changed?**

Added `link` fields on `SignalWorkflowExecutionResponse` and
`SignalWithStartWorkflowExecutionRequest`. I think a singular link
should suffice but if reviewers feel otherwise (especially w.r.t.
`SignalWithStartWorkflowExecutionRequest`) let me know.

<!-- Tell your future self why have you made these changes -->
**Why?**

To propagate backlinks on signal and signal-with-start executions back
to the caller.

<!-- Are there any breaking changes on binary or code level? -->
**Breaking changes**

Not a breaking change (unused field)

<!-- If this breaks the Server, please provide the Server PR to merge
right after this PR was merged. -->
**Server PR**

temporalio/temporal#9897
@long-nt-tran long-nt-tran force-pushed the signals-updates-backlink branch from 52c0da3 to 5209f9b Compare April 15, 2026 17:35
@long-nt-tran long-nt-tran requested review from a team as code owners April 15, 2026 17:35
@long-nt-tran long-nt-tran force-pushed the signals-updates-backlink branch from 5209f9b to 2831286 Compare April 15, 2026 18:02
@long-nt-tran long-nt-tran requested a review from bergundy April 15, 2026 18:53
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