Skip to content

Add temporal workflow signal-with-start command#758

Merged
THardy98 merged 5 commits intomainfrom
signal-with-start
Feb 21, 2025
Merged

Add temporal workflow signal-with-start command#758
THardy98 merged 5 commits intomainfrom
signal-with-start

Conversation

@THardy98
Copy link
Contributor

@THardy98 THardy98 commented Feb 20, 2025

Added temporal workflow signal-with-start command.

Description and sample usage:

  Send an asynchronous notification (Signal) to a Workflow Execution.
  If the Workflow Execution is not running or is not found, it starts the 
  workflow then sends the signal.

  ```
  temporal workflow signal-with-start \
    --signal-name YourSignal \
    --signal-input '{"some-key": "some-value"}' \
    --workflow-id YourWorkflowId \
    --type YourWorkflowType \
    --task-queue YourTaskQueue \
    --input '{"some-key": "some-value"}'
  ```
  1. Closes [Feature Request] SignalWithStartWorkflow support #332

  2. How was this tested:
    Added unit tests

  3. Any docs updates needed?
    Yes

@THardy98 THardy98 requested a review from a team February 20, 2025 21:02
@CLAassistant
Copy link

CLAassistant commented Feb 20, 2025

CLA assistant check
All committers have signed the CLA.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Description and sample usage:

      Send an asynchronous notification (Signal) to a Workflow Execution.
      If the Workflow Execution is not running or is not found, it starts the
      workflow then sends the signal.

      ```
      temporal workflow signal-with-start \
        --signal-name YourSignal \
        --signal-input '{"some-key": "some-value"}' \
        --workflow-id YourWorkflowId \
        --type YourWorkflowType \
        --task-queue YourTaskQueue \
        --input '{"some-key": "some-value"}'
      ```
@THardy98
Copy link
Contributor Author

Note: the command doesn't configure VersioningOverride in the signal-with-start request. It would basically need replicating the logic in Go SDK to convert it to proto. I opted to omit the duplication since it was marked experimental anyway and added a warning.

Let me know if we usually opt for a different approach here.

Comment on lines +311 to +317
if wfStartOpts.Memo != nil {
fields, err := encodeMapToPayloads(wfStartOpts.Memo)
if err != nil {
return err
}
memo = &common.Memo{Fields: fields}
}
Copy link
Contributor

@cretz cretz Feb 20, 2025

Choose a reason for hiding this comment

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

I think this kind of logic needs to match temporal workflow start (which uses stringKeysJSONValues for memo). In fact, looking at this in general, is there a reason not to use the Go SDK's high-level SignalWithStartWorkflow call instead of the raw RPC? We use the high-level ExecuteWorkflow call for other workflow start. Then you can just reuse the buildStartOptions helper that exists. Also I would consider moving this into commands.workflow_exec.go with its other start workflow friends.

Copy link
Contributor Author

@THardy98 THardy98 Feb 20, 2025

Choose a reason for hiding this comment

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

In fact, looking at this in general, is there a reason not to use the Go SDK's high-level SignalWithStartWorkflow call instead of the raw RPC?

There's a comment above the workflow service call below - SignalWithStartWorkflow only accepts a single arg for signal. The existing signal command on CLI uses the workflow service call because of this. I think it makes sense to provide the flexibility for multiple signal args and stay consistent with the existing CLI signal command

Copy link
Contributor

@cretz cretz Feb 20, 2025

Choose a reason for hiding this comment

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

I see, that is unfortunate that Go SDK is that way but I agree this needs to support multiple signal arguments. I fear that people that implement a new start option may not know to come update this. But I cannot think of a better way short of having Go SDK support a signal-with-start that takes multiple signal parameters. @Quinn-With-Two-Ns - thoughts here?

I do think it still may make more sense to move that encodeMapToPayloads utility that used to be for schedules only into commands.go for more generic use, and maybe move this command impl to commands.workflow_exec.go next to the other commands that work with the workflow start options.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

signal-with-start moved to commands.workflow_exec.go and encodeMapToPayloads to commands.go

@THardy98 THardy98 changed the title Add Workflow commands perform operations on Workflow Executions: Add temporal workflow signal-with-start command Feb 20, 2025
@THardy98 THardy98 changed the title Add temporal workflow signal-with-start command Add temporal workflow signal-with-start command Feb 20, 2025
Copy link
Contributor

@cretz cretz left a comment

Choose a reason for hiding this comment

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

Only minor suggestions regarding moving code a bit and providing output.

I do wonder if we should do update-with-start at the same time in case we learn something about the approach we take there that can affect signal-with-start. But maybe not since the result types/approaches are so different.

Comment on lines +311 to +317
if wfStartOpts.Memo != nil {
fields, err := encodeMapToPayloads(wfStartOpts.Memo)
if err != nil {
return err
}
memo = &common.Memo{Fields: fields}
}
Copy link
Contributor

@cretz cretz Feb 20, 2025

Choose a reason for hiding this comment

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

I see, that is unfortunate that Go SDK is that way but I agree this needs to support multiple signal arguments. I fear that people that implement a new start option may not know to come update this. But I cannot think of a better way short of having Go SDK support a signal-with-start that takes multiple signal parameters. @Quinn-With-Two-Ns - thoughts here?

I do think it still may make more sense to move that encodeMapToPayloads utility that used to be for schedules only into commands.go for more generic use, and maybe move this command impl to commands.workflow_exec.go next to the other commands that work with the workflow start options.

WorkflowIdConflictPolicy: wfStartOpts.WorkflowIDConflictPolicy,
},
)
return err
Copy link
Contributor

@cretz cretz Feb 20, 2025

Choose a reason for hiding this comment

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

The startWorkflow helper when called from workflow start prints a structured output like:

		cctx.Printer.Println(color.MagentaString("Running execution:"))
		err := cctx.Printer.PrintStructured(struct {
			WorkflowId string `json:"workflowId"`
			RunId      string `json:"runId"`
			Type       string `json:"type"`
			Namespace  string `json:"namespace"`
			TaskQueue  string `json:"taskQueue"`
		}{
			WorkflowId: run.GetID(),
			RunId:      run.GetRunID(),
			Type:       sharedWorkflowOpts.Type,
			Namespace:  c.Namespace,
			TaskQueue:  sharedWorkflowOpts.TaskQueue,
		}, printer.StructuredOptions{})

I think we should match that output here too (not much code reuse though, so just need to copy the logic probably)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added (along with a check in test for expected output)

Copy link
Contributor

@cretz cretz left a comment

Choose a reason for hiding this comment

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

This LGTM. Only reason I hesitate to mark approved is because I'd like to see at least a high-level discussed/approved design of update with start in CLI just to make sure we're not missing anything.

Comment on lines +192 to +208
err = cctx.Printer.PrintStructured(struct {
WorkflowId string `json:"workflowId"`
RunId string `json:"runId"`
Type string `json:"type"`
Namespace string `json:"namespace"`
TaskQueue string `json:"taskQueue"`
}{
WorkflowId: c.WorkflowId,
RunId: resp.RunId,
Type: c.Type,
Namespace: c.Parent.Namespace,
TaskQueue: c.TaskQueue,
}, printer.StructuredOptions{})
if err != nil {
return fmt.Errorf("failed printing: %w", err)
}
return nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
err = cctx.Printer.PrintStructured(struct {
WorkflowId string `json:"workflowId"`
RunId string `json:"runId"`
Type string `json:"type"`
Namespace string `json:"namespace"`
TaskQueue string `json:"taskQueue"`
}{
WorkflowId: c.WorkflowId,
RunId: resp.RunId,
Type: c.Type,
Namespace: c.Parent.Namespace,
TaskQueue: c.TaskQueue,
}, printer.StructuredOptions{})
if err != nil {
return fmt.Errorf("failed printing: %w", err)
}
return nil
return cctx.Printer.PrintStructured(struct {
WorkflowId string `json:"workflowId"`
RunId string `json:"runId"`
Type string `json:"type"`
Namespace string `json:"namespace"`
TaskQueue string `json:"taskQueue"`
}{
WorkflowId: c.WorkflowId,
RunId: resp.RunId,
Type: c.Type,
Namespace: c.Parent.Namespace,
TaskQueue: c.TaskQueue,
}, printer.StructuredOptions{})

Pedantic, but don't really need to wrap printing failures I don't think (even though we did in some other places)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@THardy98
Copy link
Contributor Author

This LGTM. Only reason I hesitate to mark approved is because I'd like to see at least a high-level discussed/approved design of update with start in CLI just to make sure we're not missing anything.

Ok, I can put up a separate update-with-start PR before this gets merged to get a better picture.

Copy link
Contributor

@cretz cretz left a comment

Choose a reason for hiding this comment

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

After internal discussion, this is like what we'll do with update-with-start, LGTM

@THardy98 THardy98 merged commit f968fa3 into main Feb 21, 2025
8 checks passed
@THardy98 THardy98 deleted the signal-with-start branch February 21, 2025 18:38
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.

[Feature Request] SignalWithStartWorkflow support

3 participants