Repository navigation
Conversation
4d0af10 to
5eb639f
Compare
|
Note: Cloud Integ Tests seems like failing since PR #2367 is merged |
| * @internal | ||
| * @hidden | ||
| */ | ||
| export interface NexusActivityStartContext { |
There was a problem hiding this comment.
This shouldn't be specific to Activity start. This is the context around a StartNexusOperation task and should reflect that rather than being activity specific.
Let's also move it to packages/nexus/context.ts
There was a problem hiding this comment.
StartNexusOperationTaskContext or NexusOperationTaskContext or NexusStartOperationTaskContext any other suggestions for the naming? I am leaning towards NexusStartOperationTaskContext to align with NexusStartOperationInput existing NexusCancelOperationInputtypes
There was a problem hiding this comment.
Let's also move it to /packages/nexus/context.ts
nexus package already depends on client, so moving this into packages/nexus/context.ts and having ActivityClient read it back would create a real circular package dependency. Kept it in client, exported only through internal.ts, for that reason.
There was a problem hiding this comment.
Thinking about the name made me realize we actually already have a type with these exact fields that is passed to all handlers: TemporalStartOperationContext. This is the type that should be used I think.
There was a problem hiding this comment.
Let's take a look at making these changes via an internal ActivityClientInterceptor that is appended at the end of the interceptor chain (so user interceptors run first). That way we can encapsulate this Nexus context specific changes away from this general client implementation. The interceptor can add or modify the internal options and then hopefully we won't need any changes here.
There was a problem hiding this comment.
That makes a lot of sense. I'll go with that direction.
6e78a9a to
ba0a222
Compare
| if (this._client == null) { | ||
| const base = getClient(); | ||
| const activity = new ActivityClient({ | ||
| ...base.activity.options, | ||
| interceptors: [...(base.activity.options.interceptors ?? []), this.nexusActivityStartInterceptor], | ||
| }); | ||
| this._client = Object.assign(Object.create(base), { activity }) as Client; | ||
| } | ||
| return this._client; |
There was a problem hiding this comment.
Rather than applying the interceptor here, I think we should apply the interceptor on client creation. Doing it here allows users to avoid it by calling getClient() directly. The interceptor should no-op if not in a Nexus context so it should be safe to invoke each time. We'll also need to apply the same type of interceptor to the various workflow integration points (start, signal, update, etc). If you'd like to keep this PR focused only on Activities, that's fine let's just make sure we create an issue to track.
There was a problem hiding this comment.
I would like to keep this focused on Nexus + SAA and can create an issue to track Nexus + start,signal,update
c7ec68b to
3efd787
Compare
VegetarianOrc
left a comment
There was a problem hiding this comment.
I think this looks good to me now, ty for all the updates!
Would love @chris-olszewski or @mjameswh to take a final look before merging.
chris-olszewski
left a comment
There was a problem hiding this comment.
The interceptor is a nice way to provide this behavior. Nonblocking, but a nice follow up would be asserting how this is displayed in the stack trace. (Along with injecting this interceptor at creation as was mentioned by @VegetarianOrc)
`TemporalNexusClient.startActivity()` guards the one Activity start that can complete a Nexus operation, but a handler that starts additional Activities must call the raw client directly -- either `nexusClient.client.activity.start(...)` or the module-level `getClient()` export. Neither of those raw starts inherited the inbound Nexus request ID or links, so a Nexus-task redelivery could start a duplicate Activity instead of resolving to its original run. Activities started through either raw path now inherit the handler's request ID and inbound links. When the server returns an Activity response link, it is added to the operation's outbound links. Completion callbacks remain limited to the guarded start, since only that start can complete the operation. Implemented as `nexusActivityStartInterceptor`, an `ActivityClientInterceptor` installed once on the Worker's Client (`compileWorkerInterceptors`), gated by an ambient per-task context so it is a no-op outside an active Nexus operation. Because it is installed once at Client construction rather than reconstructed per-invocation, it applies uniformly whether an Activity is started by the operation handler itself or by an inbound interceptor, and whether reached via `nexusClient.client` or the plain `getClient()` export. Aligns with sdk-go #2633 and sdk-java #3048.
82c56f7 to
507270c
Compare
Summary
TemporalNexusClient.startActivity()guards the one Activity start that can complete a Nexus operation, but a synchronous handler that starts additional Activities must call the rawActivityClient. Those starts previously omitted the inbound Nexus request ID and links, so a Nexus-task redelivery could start a duplicate Activity instead of resolving to its original run.Raw Activity starts now inherit the handler’s request ID and inbound links. Completion callbacks remain limited to the guarded start, since only that start can complete the operation.
Aligns with the sdk-go PR #2633 and sdk-java PR #3048.
Changes
startOperationhandler invocation.ActivityClientstarts inherit the inbound Nexus request ID and links.Testing