Skip to content

Add SAA TemporalNexusOperation handling#1565

Draft
VegetarianOrc wants to merge 16 commits into
mainfrom
amazzeo/temporal-nexus-operation-handler-saa
Draft

Add SAA TemporalNexusOperation handling#1565
VegetarianOrc wants to merge 16 commits into
mainfrom
amazzeo/temporal-nexus-operation-handler-saa

Conversation

@VegetarianOrc

Copy link
Copy Markdown
Contributor

What was changed

Added start_activity support for Temporal Nexus operation handlers.

  • Added activity-backed Temporal Nexus operation handling and cancellation support.
  • Adjusted the existing start_workflow path to share the backing context, token, and handler behavior needed for activity support.
  • Added activity link conversion support.
  • Expanded operation token, link conversion, temporal operation, and type coverage tests.

Why?

Temporal Nexus operations should be able to start and cancel activities as well as workflows, using a consistent operation token and backing-operation model across both paths.

Checklist

  1. How was this tested:
    Added/updated coverage in:
  • tests/nexus/test_temporal_operation.py
  • tests/nexus/test_operation_token.py
  • tests/nexus/test_link_conversion.py
  • tests/nexus/test_nexus_type_errors.py
  1. Any docs updates needed?
    Yes. Docs should cover start_activity support for Temporal Nexus operation handlers, including operation tokens, cancellation behavior, and activity link handling.

Expose customizable Temporal Nexus operation handlers and client support.

Add activity link conversion, operation token handling, and related tests.
@VegetarianOrc VegetarianOrc changed the title Add SAA Temporal Nexus operation handling Add SAA TemporalNexusOperation handling May 29, 2026
Comment thread temporalio/nexus/_token.py
case "activity":
return activity_link_to_nexus_link(temporal_link.activity)

case "batch_job" | "workflow":

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just future proofing - if this comes through with a unknown value, it will be unhandled - should this be case _ and come after the none instead of specifying two values?

Also you might put the case value in the error message, it would be nice to know when debugging what value was actually recieved.

return nexusrpc.Link(url=url, type=_LinkType.NEXUS_OPERATION.value)


def activity_link_to_nexus_link(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I don't see any failure handling in this - if urlunparse fails for example, is everything logged and handled in that call?

In looking for failure handling I looked for some unit tests on this method and didn't see any (though I did for nexus_link_to_activity_link). Should there be some tests?

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.

urlunparse only raises when invalid arguments are supplied so in this case where we constructing the input tuple from known string components we're safe. In terms of logging, should the conversion ever raise, the usage in _operation_context.py catches the conversion error and logs a warning that includes the error. This function is used indirectly via temporal_link_to_nexus_link.

This function is exercised in test_link_conversion_nexus_link_to_activity_link where there are a few conversions between nexusrpc.Link <--> proto links for the activity flavor.

match operation_token.type:
case OperationTokenType.WORKFLOW:
options = CancelWorkflowRunOptions(
if not operation_token.workflow_id:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

decode is called above, and the decode method already throws a TypeError if it is missing the workflow or activity ID isn't it? (Lines 99 and 116.) So the error check for workflow here and activity below will never throw, but also might mislead users as they would expect a HandlerErrorType but get a TypeError.

"Invalid activity operation token: missing activity ID",
type=HandlerErrorType.NOT_FOUND,
)
if not operation_token.run_id:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The decode method doesn't check for run_id like it does the other two - should it? It's nice to have all the error checking on one place, but I don't know if that would affect other things. If not, then this should probably throw TypeError just to stay consistent with the other checks.

(trying to be overly clearn - token.py does check run id, but the other two have two checks - runId is missing the second check.)


query_params = urllib.parse.parse_qs(url.query)

match query_params.get(LINK_RUN_ID_PARAM_NAME):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

When this rolls out, is there any chance links previously serialized with runId as a parameter will be hit? Should this be able to deserialize those to avoid a migration issue? Otherwise things might go out of sync and runId would get lost here.

LINK_RUN_ID_PARAM_NAME: op_link.run_id,
},
)
run_id = urllib.parse.quote(op_link.run_id, safe="")

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 there be an error check for namespace, operation_id, and run_id to make sure they got values? Or are we certain these will always be present and so no need to check? Or is is just fine and we'll get a bad URL which will give us a reasonable error later?

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