API surface area for worker callbacks#836
Conversation
bergundy
left a comment
There was a problem hiding this comment.
You're missing a new link definition to a callback on an execution.
| // Nexus task queue the Temporal worker is listening on. | ||
| // | ||
| // NOTE: This is not a temporal.api.taskqueue.v1.TaskQueue to avoid a circular dependency. | ||
| string taskqueue_name = 1; |
There was a problem hiding this comment.
nit: we call this field task_queue everywhere, it will generate better across languages with the underscore. Rename to task_queue_name.
There was a problem hiding this comment.
Asking because I'm not sure: is it a problem that we aren't using the proper TaskQueue proto type here?
This is the full proto definition. We'd be missing out on the kind and normal_name of task queue. And just assuming it's TASK_QUEUE_KIND_NORMAL. (And never TASK_QUEUE_KIND_WORKER_COMMANDS or TASK_QUEUE_KIND_STICKY.)
Could that be a problem down the road?
| temporal.api.sdk.v1.UserMetadata user_metadata = 16; | ||
|
|
||
| // Completion callbacks to be invoked once the Nexus operation reaches a terminal state. | ||
| repeated temporal.api.common.v1.Callback completion_callbacks = 17; |
There was a problem hiding this comment.
You'll need to add the full attachment support that we have for request IDs and on conflict options for workflows and activities.
There was a problem hiding this comment.
Would you mind elaborating on what you mean by this? What do you mean by "full attachment" here?
I'm patterning this after the way we added completion callbacks to StartActivityExecutionRequest and StartWorkflowExecutionRequest. I see in both of those other request types there are id_conflict_policy / id_reuse_policy fields. But StartNexusOperationExecutionRequest has similar fields as well.
Are you saying that each individual commonpb.Callbacks should have its own (potentially user-supplied) callback_id ? And ID Conflict/Reuse policies supplied too? That doesn't make sense to me. Since if the SANO is accepted by Temporal, the callbacks should be accepted as well. (And I don't see any sort of UpdateNexusOperationExecution-type command, that would allow us to merge/update callbacks?)
334ee1f to
1329a40
Compare
|
@bergundy Thanks for the review, please take another look.
|
| string request_id = 3; | ||
| } | ||
|
|
||
| string callback_id = 1; |
There was a problem hiding this comment.
There's no callback_id to refer to in all of our models.
There was a problem hiding this comment.
A SANO operation could have multiple worker callbacks associated with it. So in order for the link to not be ambiguous, we need some sort of unique identifier for which callback on the SANO.
The user would be able to see those IDs on the workflowservice.CallbackExecutionInfo messages, returned from DescribeNexusOperationExecution.
Does that sound right? Or is it that we don't actually need to have callback_id here?
There was a problem hiding this comment.
That's what the request ID is for.
There was a problem hiding this comment.
I don't follow. Would you mind elaborating on that? ... in fact, what does NexusOperationCompletion::request_id mean in this context?
Would that be the request_id that was sent when we go and invoke the worker callback? (e.g. the nexuspb.StartOperationRequest::request_id that is sent to the worker?)
| Activity activity = 3; | ||
| NexusOperation nexus_operation = 4; | ||
| Workflow workflow = 5; | ||
| Callback callback = 6; |
There was a problem hiding this comment.
Maybe just flatten the Callback into this variant? NexusOperationCompletionCallback? Or just NexusOperationCallback?
There was a problem hiding this comment.
I can be convinced otherwise, but I'm inclined to keep it as-is. Let me know if you disagree.
When we later support attaching worker callbacks to Workflows and Activities, it would be kind of lame to have unique kinds of links for those. e.g. WorkflowCompletionCallback and ActivityCompletionCallback. Do we want to treat those as three different kinds of Links or just a Link to a callback, which can be pointing to different resources?
| temporal.api.sdk.v1.UserMetadata user_metadata = 16; | ||
|
|
||
| // Completion callbacks to be invoked once the Nexus operation reaches a terminal state. | ||
| repeated temporal.api.common.v1.Callback completion_callbacks = 17; |
1a13720 to
c176d77
Compare
|
Rebased and force-pushed. @bergundy PTAL. Though that last one re: "full attachment" will probably need a sync conversation, as I'm not sure what you're asking for there. Here are the open questions/threads remaining:
|
| } | ||
|
|
||
| message CallbackExecutionOutcome { | ||
| oneof value { | ||
| // The callback completed successfully. (Which may include delivering a "failed" result successfully.) | ||
| google.protobuf.Empty success = 1; | ||
| // The failure if the callback was not able to complete successfully. e.g. timed out, received an | ||
| // unretriable error, etc. | ||
| temporal.api.failure.v1.Failure failure = 2; | ||
| } | ||
| } | ||
|
|
||
| message CallbackExecutionInfo { | ||
| // Identifier of the callback's execution. Unique within the containing namespace. | ||
| string callback_id = 1; | ||
|
|
||
| CallbackInfo info = 2; | ||
| CallbackExecutionOutcome outcome = 3; | ||
| } | ||
|
|
There was a problem hiding this comment.
| } | |
| message CallbackExecutionOutcome { | |
| oneof value { | |
| // The callback completed successfully. (Which may include delivering a "failed" result successfully.) | |
| google.protobuf.Empty success = 1; | |
| // The failure if the callback was not able to complete successfully. e.g. timed out, received an | |
| // unretriable error, etc. | |
| temporal.api.failure.v1.Failure failure = 2; | |
| } | |
| } | |
| message CallbackExecutionInfo { | |
| // Identifier of the callback's execution. Unique within the containing namespace. | |
| string callback_id = 1; | |
| CallbackInfo info = 2; | |
| CallbackExecutionOutcome outcome = 3; | |
| } | |
| // TODO document me | |
| CallbackExecutionOutcome outcome = 9; | |
| } | |
| message CallbackExecutionOutcome { | |
| oneof value { | |
| // The callback completed successfully. (Which may include delivering a "failed" result successfully.) | |
| google.protobuf.Empty success = 1; | |
| // The failure if the callback was not able to complete successfully. e.g. timed out, received an | |
| // unretriable error, etc. | |
| temporal.api.failure.v1.Failure failure = 2; | |
| } | |
| } |
There was a problem hiding this comment.
I wasn't sure how concerned we'd be with including the failure objects in CallbackInfo, so I created the separate -ExecutionInfo. But I'm happy to make the change to just add the -ExecutionOutcome as a field to CallbackInfo. (And existing callsites would just leave it blank, and maybe we'd wire through a bool include_outcome field in the request object or something.)
| string request_id = 3; | ||
| } | ||
|
|
||
| string callback_id = 1; |
There was a problem hiding this comment.
That's what the request ID is for.
| Activity activity = 3; | ||
| NexusOperation nexus_operation = 4; | ||
| Workflow workflow = 5; | ||
| Callback callback = 6; |
| message OnCompleteRequest { | ||
|
|
||
| // The outcome of the source operation. | ||
| message Outcome { |
There was a problem hiding this comment.
Might be worth defining Outcome in common at this point.
There was a problem hiding this comment.
I tried, but it would require some more refactoring since that would lead to a circular dependency between commonpb and failurepb. Maybe we could expose some other or simpler error type in the Outcome::failure case. But the failurepb.Failure seems kinda useful in how it strongly types various categories of errors.
|
|
||
| // Completion callbacks to be invoked once the Nexus operation reaches a terminal state. | ||
| // They will remain in the CALLBACK_STATE_STANDBY state until the Nexus operation is finished. | ||
| repeated temporal.api.callback.v1.CallbackExecutionInfo completion_callbacks = 7; |
There was a problem hiding this comment.
| repeated temporal.api.callback.v1.CallbackExecutionInfo completion_callbacks = 7; | |
| repeated temporal.api.nexusoperation.v1.CallbackInfo callbacks = 7; |
And copy from
api/temporal/api/activity/v1/message.proto
Line 233 in f53963d
There was a problem hiding this comment.
Ack, will get to in the next rev. And having different CallbackInfo objects defined in different namespaces (e.g. /activity, /nexusoperation will sidestep some other problems we might have.)
Co-authored-by: Roey Berman <roey.berman@gmail.com>
feature/worker-callbacksbranch with this.What changed?
Adds the API surface area for the WIP worker callbacks feature.
Specifically, the changes are:
completion_callbacksfield toStartNexusOperationExecutionRequest. (How worker callbacks will be sent to the server.)Workervariant ofcommonpb.Callback. (How worker callbacks will be encoded.)notificationservice/v1/request_response.prototo define the input/output shape for worker callbacks. (The payload that will be delivered to workers.)Why?
Today it is cumbersome to durably invoke Nexus operations and execute logic based on their results. "Worker callbacks" is a capability being developed that would allow developers to attach a Nexus operation to a SANO. Later, when the SANO reaches a terminal state, the attached Nexus operation would be invoked.
Breaking changes
None.
Server PR
TBD. The current prototype (based on the
feature/worker-callbacksbranch in this repo) can be found at:https://github.com/temporalio/temporal/compare/feature/worker-callbacks?expand=1