Skip to content

Add support for Standalone Nexus Operations#1046

Open
Quinn-With-Two-Ns wants to merge 1 commit into
mainfrom
NEXUS-332
Open

Add support for Standalone Nexus Operations#1046
Quinn-With-Two-Ns wants to merge 1 commit into
mainfrom
NEXUS-332

Conversation

@Quinn-With-Two-Ns
Copy link
Copy Markdown
Contributor

@Quinn-With-Two-Ns Quinn-With-Two-Ns commented May 21, 2026

What changed?

Add support for stand alone nexus operations to the CLI.

Checklist

Stability

  • Breaking changes are marked with 💥 in the PR title and release notes
  • Changes to JSON output (-o json / -o jsonl) are treated as breaking changes

Design

  • This feature does not depend on Cloud-only APIs or behavior (it works against an OSS server)
  • New commands follow temporal <noun> <verb> structure (e.g. temporal workflow start)
  • New flags are named after the API concept, not the implementation mechanism (good: --search-attribute, bad: --index-field)
  • New flags don't duplicate an existing flag that serves the same purpose
  • New flags do not have short aliases without strong justification
  • Experimental features are marked with (Experimental) in commands.yaml

Help text (see style guide at the top of commands.yaml)

  • All flags shown in help text and examples are implemented and functional
  • Summaries use sentence case and have no trailing period
  • Long descriptions end with a period and include at least one example invocation
  • Examples use long flags (--namespace, not -n), one flag per line
  • Placeholder values use YourXxx form (YourWorkflowId, YourNamespace)

Behavior

  • Results go to stdout; errors and warnings go to stderr
  • Error messages are lowercase with no trailing punctuation

Tests

  • Added functional test(s) (SharedServerSuite)
  • Added unit test(s) (func TestXxx) where applicable

Manual tests

Setup

  temporal operator nexus endpoint create                                                                                                  
      --name my-endpoint                                                                                                                 
      --target-namespace default
      --target-task-queue my-tq

Happy path

  $ temporal nexus operation start                                                                                                         
      --endpoint my-endpoint      
      --service my-service                                                                                                                 
      --operation my-op                                                                                                                  
      --operation-id my-op-1
      --input '"hello"'     
  Started Nexus Operation:                                                                                                                 
    Endpoint    my-endpoint
    Service     my-service                                                                                                                 
    Operation   my-op                                                                                                                    
    OperationId my-op-1
    RunId       7e7c8b2a-...-...
    Namespace   default

Error case

  $ temporal nexus operation start                                                                                                         
      --service my-service                                                                                                                 
      --operation my-op   
      --operation-id my-op-2                                                                                                               
  Error: required flag(s) "endpoint" not set                                                                                             

Composition — start an operation, then fetch its result, then list/describe:

  $ temporal nexus operation start
      --endpoint my-endpoint                                                                                                               
      --service my-service                                                                                                               
      --operation my-op                                                                                                                    
      --operation-id my-op-3
      --input '"world"'                                                                                                                    
                                                                                                                                         
  $ temporal nexus operation result --operation-id my-op-3
  Results:                                                                                                                                 
    Status  COMPLETED
    Result  "got: world"                                                                                                                   
                                                                                                                                         
  $ temporal nexus operation describe --operation-id my-op-3
    OperationId            my-op-3
    RunId                  7e7c8b2a-...-...                                                                                                
    Endpoint               my-endpoint
    Service                my-service                                                                                                      
    Operation              my-op                                                                                                         
    Status                 Succeeded                                                                                                       
    ...

Copy link
Copy Markdown

@Evanthx Evanthx left a comment

Choose a reason for hiding this comment

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

Found a few nit-picks! Your call on whether they are worth addressing, they are all quite minor.

if err := printNexusOperationFailure(cctx, operationID, runID, v.Failure); err != nil {
cctx.Logger.Error("Nexus operation failed, and printing the output also failed", "error", err)
}
return fmt.Errorf("nexus operation failed")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should Nexus be capitalized? Same for line 112 above and 131, 492 below. Didn't do a complete check for places, but looking at the code for "fmt.Errorf.*nexus" I see it both ways!

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.

in errors it should be lower case based on convention, same as workflow and logs it may be uppercase

// Matches the SDK's pollActivityTimeout in internal_activity_client.go.
const pollNexusOperationTimeout = 60 * time.Second

// pollNexusOperationOutcome polls for a nexus operation result using a
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Feel free to ignore this comment - would this be better as a method on Handle then, both for reuse and so that if someone made a change to Handle.Get later this method would be visible there to get the equivalent change? ie, maybe Handle would then have a Get and a RawGet method, something like that?

Comment thread internal/temporalcli/commands.nexus_operation.go Outdated
}
resultJSON, err := json.Marshal(valuePtr)
if err != nil {
return fmt.Errorf("failed marshaling result: %w", err)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Line 202 and 210 return the exact same string as 177 and 184. So if we get that error, we won't actually know which line failed, just that it's one of those two. Given that they are doing the same thing to the same object it might not matter much, but it's nice to just go to the offending log line without having to wonder which line it was.

Comment thread internal/temporalcli/commands.nexus_operation.go Outdated
Comment thread internal/temporalcli/commands.nexus_operation_test.go Outdated
Copy link
Copy Markdown

@VegetarianOrc VegetarianOrc left a comment

Choose a reason for hiding this comment

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

A few minor nits, but looks good to me!

Comment thread internal/temporalcli/commands.yaml Outdated
Comment thread internal/temporalcli/commands.yaml Outdated
Comment thread internal/temporalcli/commands.yaml Outdated
Comment thread internal/temporalcli/commands.yaml Outdated
Comment thread internal/temporalcli/commands.nexus_operation.go Outdated
@Quinn-With-Two-Ns Quinn-With-Two-Ns marked this pull request as ready for review June 3, 2026 16:08
@Quinn-With-Two-Ns Quinn-With-Two-Ns requested a review from a team as a code owner June 3, 2026 16:08
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