Skip to content

💥 Adding links to Nexus signals#2114

Open
Evanthx wants to merge 18 commits into
mainfrom
signal-links
Open

💥 Adding links to Nexus signals#2114
Evanthx wants to merge 18 commits into
mainfrom
signal-links

Conversation

@Evanthx

@Evanthx Evanthx commented Jun 11, 2026

Copy link
Copy Markdown

This adds links to Nexus signals - the receiving workflow has a link to the workflow sending the signal. and the sending workflow has a link to the receiving workflow.

@Evanthx Evanthx requested a review from a team as a code owner June 11, 2026 17:18

@VegetarianOrc VegetarianOrc 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.

Unsure if the CI failures are directly related to these changes, but please take a look and ensure they're passing.

Comment thread packages/client/src/internal.ts Outdated
Comment on lines +39 to +44
/**
* Backlink copied by the client from the SignalWithStartWorkflowExecutionResponse.
* Only populated by servers that support CHASM signal backlinks (1.31 and up); left unset
* otherwise.
*/
signalBackLink?: temporal.api.common.v1.ILink;

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.

Is there a scenario where backLink and signalBackLink are both populated? If not we should remove this and use the one field.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch, consolidated them

Comment thread packages/client/src/workflow-client.ts Outdated
* {@link Client.workflow} to interact with Workflows.
*/
export class WorkflowClient extends BaseClient {
export class WorkflowClient extends BaseClient implements InternalWorkflowClientWithNexusLinks {

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.

We shouldn't implement this interface here as it leaks the method onto client.workflow. I don't have a great suggestion for exposing signal to do the internal options dance though. One option might be to hide the method behind an internal symbol. Let's sync with @chris-olszewski and come up with what feels like the best path here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Changed as per our conversation!

Comment thread packages/client/src/interceptors.ts Outdated
Comment on lines +93 to +100
/**
* SDK-internal options used by the Temporal Nexus helpers to forward inbound Nexus links onto
* the signal request and to capture the backlink returned on the response.
*
* @internal
* @hidden
*/
readonly [InternalWorkflowSignalOptionsSymbol]?: InternalWorkflowSignalOptions[typeof InternalWorkflowSignalOptionsSymbol];

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.

We shouldn't leak these internal details here. instead we should define an internal interface in internal.ts that extends WorkflowSignalInput and adds this symbol.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed

Comment thread packages/client/src/workflow-client.ts Outdated
protected async _signalWorkflowHandler(input: WorkflowSignalInput): Promise<void> {
const dataConverter = this.dataConverter;
const context = this.workflowSerializationContext(input.workflowExecution.workflowId!);
const internalOptions = input[InternalWorkflowSignalOptionsSymbol];

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.

Suggested change
const internalOptions = input[InternalWorkflowSignalOptionsSymbol];
const internalOptions = (input as InternalWorkflowSignalInput)[InternalWorkflowSignalOptionsSymbol];

Going along with my above comment about not leaking this symbol, this should be cast to an internal type here and the internal options retrieved from that. In my suggested change I made up a name, but feel free to use something more appropriate.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Hopefully fixed as per our conversation!

Comment thread packages/nexus/src/workflow-helpers.ts Outdated
* NexusOperation history event back to the callee Workflow's event. No-op when the server did not
* return a backlink (older servers, or CHASM signal backlinks disabled).
*/
function pushBacklink(ctx: nexus.StartOperationContext, backLink: temporal.api.common.v1.ILink | undefined): void {

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: the backLink arg should probably not accept undefined. Call sites look like they have a side effect, but in reality may not do anything.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Now checked


export const pingSignal = workflow.defineSignal<[string]>('ping');

export async function caller(endpoint: string, input: string): Promise<string> {

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.

Let's remove the concept of the mode switch here and have separate caller workflows and operation handlers as needed for each test. Ideally we can colocate these right above where they're used to make it easier to see the full picture of what runs as part of the test.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done


export async function caller(endpoint: string, input: string): Promise<string> {
const client = workflow.createNexusServiceClient({ endpoint, service: signalingService });
const [mode, rest] = splitFirst(input, ':');

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.

My above comment stands about separating this out, but just want to call out that we should avoid encoding params as strings and instead use objects.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done

Comment on lines +320 to +322
async function fetchHistory(client: any, workflowId: string): Promise<temporal.api.history.v1.IHistory> {
return await client.workflow.getHandle(workflowId).fetchHistory();
}

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.

Let's remove this helper and just get a handle where necessary to get the history. There's a few places where we already get or have a handle that then call this helper.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done

Comment thread packages/test/src/test-nexus-signal-linking.ts Outdated
Comment thread packages/test/src/test-nexus-signal-linking.ts Outdated
@Evanthx Evanthx requested a review from VegetarianOrc June 18, 2026 00:46
@VegetarianOrc VegetarianOrc changed the title Adding links to Nexus signals 💥 Adding links to Nexus signals Jun 24, 2026
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.

2 participants