Skip to content

Klassenq/nexus per endpoint encryption - #872

Draft
JoshuaFrenchwood wants to merge 7 commits into
mainfrom
klassenq/nexus-per-endpoint-encryption
Draft

JoshuaFrenchwood wants to merge 7 commits into
mainfrom
klassenq/nexus-per-endpoint-encryption

Conversation

@JoshuaFrenchwood

Copy link
Copy Markdown

What changed?
Added PropagatedNexusSerializationContext with endpoint, service, and operation fields. Added it to workflow, activity, and update APIs, including start requests, task poll responses, workflow details, and the workflow-started history event.

Why?
Nexus callers need their serialization context carried to the entities they start. Recording it in workflow history also lets replay and reset restore that context

Breaking changes

Server PR

Record the context on the workflow started event so mutable-state rebuilds and resets restore it through normal replay.

Constraint: Reset rebuilds mutable state from history.
Rejected: Copy context directly in workflow resetter | bypasses standard event reconstruction.
Confidence: high
Scope-risk: moderate
Tested: make buf-lint api-linter go-grpc fix-path
Not-tested: make grpc (blocked by pre-existing WorkerHeartbeat.environment breaking-change failure)

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

Apologies in advance if these are all non-concerns.

Comment thread temporal/api/common/v1/message.proto Outdated
message PropagatedNexusSerializationContext {
string endpoint = 1;
string service = 2;
// If more context is needed, this message can be extended with additional fields.

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: Isn't this kinda implied with any protobuf message contract? Seems like we can just remove this comment entirely.

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.

Agreed, I removed that comment

Comment thread temporal/api/common/v1/message.proto Outdated
map<string, Payload> fields = 1;
}

// PropagatedNexusSerializationContext represents the context of the Nexus caller that started this entity.

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: Would "execution" or "resource" be a better term 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.

Updated to use execution here

Comment thread temporal/api/common/v1/message.proto Outdated

// PropagatedNexusSerializationContext represents the context of the Nexus caller that started this entity.
// If multiple Nexus callers attempt to attach to the same entity the server will verify that
// each field matches, if any field does not match then the request will be rejected.

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.

What about situations where multiple Nexus handlers are backed by the same Temporal execution?

e.g. a Nexus Service with two Nexus handlers, each of which spawns a standalone Activity, with the ID Conflict policy USE_EXISTING. The first call would create the SAA. The second Nexus handler would need to provide a different PropagatedNexusSerializationContext to that SAA, right? (And attach another completion callback, so that when the SAA completes, both Nexus handlers would effective return to their callers.)

Am I missing something about how this is supposed to work?

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.

In the current design the second request will be rejected. So when using USE_EXISTING conflict policy, you would have to have the same PropagatedNexusSerializationContext.

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.

So Nexus handlers with different endpoint, service or operation cannot share the same backing execution (Workflow or SAA)

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.

Thanks for the clarification. Let ping you offline to chat about this more, since I don't know how much of a problem that would be in-practice. (And just want to make sure we've thought it through and are OK with the limitation.)

e.g. I can imagine scenarios where a user would want to expose the same Nexus service from different endpoints, since that would allow you to manually set up things like having different rate limits or worker pools. At least as a workaround until we can expand upon the configuration knobs available in TCloud.

Even then, it might be acceptable... since you would at least control the code at the callsite wherever you specify the USE_EXISTING conflict policy. (And could therefore opt to not do that if doing so would lead to problems.)

temporal.api.common.v1.OnConflictOptions on_conflict_options = 21;
// Time to wait before making the first activity task available for dispatch. This delay is not applied to retry attempts.
google.protobuf.Duration start_delay = 22;
// Serialization context propagated from the Nexus caller that started this activity.

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 need to add this PropagateNexusSerializationContext to every Start- and Describe- operation, for each kind of execution. Right?

If so, it looks like we missed standalone Nexus operations. e.g. NexusOperationExecutionInfo and StartNexusOperationExecutionRequest.

https://github.com/temporalio/api/blob/main/temporal/api/nexus/v1/message.proto#L246

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.

For those they already have the operation/service/endpoint, so we dont need to add this there.

Comment thread temporal/api/common/v1/message.proto Outdated
// PropagatedNexusSerializationContext represents the context of the Nexus caller that started this execution.
// Nexus callers can share a workflow or standalone activity with USE_EXISTING only when their
// endpoint, service, and operation match. A request with a different context is rejected.
message PropagatedNexusSerializationContext {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can put this in the nexus package if there are no circular import concerns.

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.

Moved to nexus package

// according to the weights.
temporal.api.taskqueue.v1.PollerGroupsInfo poller_groups_info = 19;
// Serialization context propagated from the Nexus caller that started this workflow.
temporal.api.common.v1.PropagatedNexusSerializationContext propagated_nexus_serialization_context = 20;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we need this here given that we have it on the WorkflowExecutionStarted event attributes?

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.

The History field in PollWorkflowTaskQueueResponse has WorkflowExecutionStarted attributes, but the comment above it says that partial histories may be sent to workers that are using sticky queue. So I included here directly

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The worker can store this information per workflow run though. I don't see a good enough reason to send it with every task.

@bergundy

Copy link
Copy Markdown
Member

Please do not merge this until you have a working end to end prototype using the server and a single SDK.

@JoshuaFrenchwood
JoshuaFrenchwood marked this pull request as draft September 30, 2026 17:34
// PropagatedNexusSerializationContext represents the context of the Nexus caller that started this execution.
// Nexus callers can share a workflow or standalone activity with USE_EXISTING only when their
// endpoint, service, and operation match. A request with a different context is rejected.
message PropagatedNexusSerializationContext {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggesting that we don't stutter here, we're already in the nexus package.

Suggested change
message PropagatedNexusSerializationContext {
message PropagatedSerializationContext {

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.

4 participants