Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Nexus SignalWorkflowOperation #1770

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open

Conversation

pdoerner
Copy link
Contributor

@pdoerner pdoerner commented Jan 10, 2025

What was changed

Added a new type of synchronous Nexus operation for sending signals.

Why?

Convenience and request ID + links handling.

Checklist

  1. Closes

  2. How was this tested:

New functional tests

  1. Any docs updates needed?

@pdoerner pdoerner marked this pull request as ready for review January 10, 2025 17:56
@pdoerner pdoerner requested a review from a team as a code owner January 10, 2025 17:56
Comment on lines 44 to 45
//
// Exposed as: [go.temporal.io/sdk/interceptor.Interceptor]
Copy link
Member

Choose a reason for hiding this comment

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

Hmm... how did this happen? @Quinn-With-Two-Ns looks like this is the third time this got repeated.

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 originally aliased temporalnexus.SignalWorkflowInput to this type and added it to the comment but then undid that and aliased it to the internal type. The automated tools complained about the checks until I ran with -fix which I guess just added another line again.

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 just went ahead and manually removed all the duplicates

Copy link
Contributor

Choose a reason for hiding this comment

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

@yuandrew FYI might be a bug in your alias tool

// NewSignalWorkflowOperation is a helper for creating a synchronous nexus.Operation to deliver a signal.
//
// NOTE: Experimental
func NewSignalWorkflowOperation(name string) nexus.Operation[SignalWorkflowInput, nexus.NoValue] {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
func NewSignalWorkflowOperation(name string) nexus.Operation[SignalWorkflowInput, nexus.NoValue] {
func NewWorkflowSignalOperation[T any](name string, func(ctx context.Context, input T, options nexus.StartOpertionOptions) SignalWorkflowInput) nexus.Operation[T, nexus.NoValue] {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So why require users to pass in a function to extract the required parameters from T instead of just giving them an input type which contains all the required values (wf ID, run ID, signal name, and signal arg)?

Copy link
Member

Choose a reason for hiding this comment

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

The caller doesn't care that this is a signal, that's the handler's call.

var out string
require.NoError(t, run.Get(ctx, &out))
require.Equal(t, "nexus", out)

Copy link
Member

Choose a reason for hiding this comment

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

Test the request ID and links are properly attached.

test/nexus_test.go Outdated Show resolved Hide resolved
@@ -94,6 +93,28 @@ func NewSyncOperation[I any, O any](
}
}

// SignalWorkflowInput is the input to a NewSignalWorkflowOperation.
type SignalWorkflowInput = internal.ClientSignalWorkflowInput
Copy link
Member

Choose a reason for hiding this comment

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

Don't reuse the type from the interceptors, you want a type that contains the workflow ID, optional run ID and signal name.

@Quinn-With-Two-Ns
Copy link
Contributor

Did we test what happens in a failure case like we signal a workflow that does not exist? I would think we would want that to fail the operation?

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.

This is almost good to go AFAIC.

Something to consider here is that the behavior is different from the WorkflowRunOperation where the default is to pass through the operation input as workflow input. I'm wondering if users will find this inconsistency confusing.

@Quinn-With-Two-Ns you may want to comment on this.

@@ -94,6 +93,38 @@ func NewSyncOperation[I any, O any](
}
}

// SignalWorkflowInput is the input to a NewSignalWorkflowOperation.
Copy link
Member

Choose a reason for hiding this comment

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

Please fix the docstring. It's not the input to the operation.

Comment on lines +98 to +101
WorkflowID string
RunID string
SignalName string
Arg any
Copy link
Member

Choose a reason for hiding this comment

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

Please document all of the public API fields.

// NewSignalWorkflowOperation is a helper for creating a synchronous nexus.Operation to deliver a signal.
//
// NOTE: Experimental
func NewSignalWorkflowOperation[T any](
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
func NewSignalWorkflowOperation[T any](
func NewWorkflowSignalOperation[T any](

}

// NewSignalWorkflowOperation is a helper for creating a synchronous nexus.Operation to deliver a signal.
//
Copy link
Member

Choose a reason for hiding this comment

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

Also call out that this ensures idempotency via the request ID mechanism (to some degree - violated if the workflow spans multiple runs) and the bidi linking is also important to call out (for now it's only uni-directional but we'll fix that).

@Quinn-With-Two-Ns
Copy link
Contributor

Something to consider here is that the behavior is different from the WorkflowRunOperation where the default is to pass through the operation input as workflow input. I'm wondering if users will find this inconsistency confusing.

I think the difference here is signal needs to know the workflow ID, where as starting a workflow generates the workflow ID. I am not strongly apposed to adding both for signal, I just worry it would encourage a design where uses are passing their workflow IDs in their signal inputs

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