Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions nexus-messaging/src/callerpattern/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
## Caller pattern

The handler worker starts a `GreetingWorkflow` for a user ID at boot.
`NexusGreetingService` holds that ID and routes every Nexus operation to it.
`nexusGreetingServiceHandler` derives the workflow ID and routes every Nexus operation to it.
The caller's input does not have that workflow ID as the caller doesn't know it -- but the caller sends in the User ID,
and `NexusGreetingService` knows how to get the desired workflow ID from that User ID (via the `GreetingWorkflow_for_<userId>` prefix).
and `nexusGreetingServiceHandler` knows how to get the desired workflow ID from that User ID (via the `GreetingWorkflow_for_<userId>` prefix).

The handler worker uses the same prefix to generate a workflow ID from a user ID when it launches the workflow.

Expand All @@ -16,19 +16,24 @@ The caller workflow:

### Running

Start a Temporal server:
Start a compatible Temporal dev server with Workflow Update callbacks enabled:

```bash
temporal server start-dev
./temporal server start-dev \

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.

I think we would also need history.enableCHASMSignalBacklinks

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.

Thanks, updated

--dynamic-config-value history.enableCHASMCallbacks=true \
--dynamic-config-value history.enableUpdateCallbacks=true \
--dynamic-config-value history.enableCHASMSignalBacklinks=true \
--namespace nexus-messaging-handler-namespace \
--namespace nexus-messaging-caller-namespace
```

Create the namespaces and Nexus endpoint:
This sample requires a Temporal dev-server build that supports Workflow Update callbacks. Download the compatible
binary from the [Temporal CLI pre-release instructions](https://docs.temporal.io/standalone-nexus-operation#temporal-cli-support).

```bash
temporal operator namespace create --namespace nexus-messaging-handler-namespace
temporal operator namespace create --namespace nexus-messaging-caller-namespace
Create the Nexus endpoint:

temporal operator nexus endpoint create \
```bash
./temporal operator nexus endpoint create \
--name nexus-messaging-nexus-endpoint \
--target-namespace nexus-messaging-handler-namespace \
--target-task-queue nexus-messaging-handler-task-queue
Expand Down
47 changes: 27 additions & 20 deletions nexus-messaging/src/callerpattern/service/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,34 @@ function workflowIdForUser(userId: string): string {
}

export const nexusGreetingServiceHandler = nexus.serviceHandler(nexusGreetingService, {
getLanguages: async (ctx, input: GetLanguagesInput) => {
const client = temporalNexus.getClient();
const handle = client.workflow.getHandle(workflowIdForUser(input.userId));
return await handle.query(getLanguagesQuery);
},
getLanguages: new temporalNexus.TemporalOperationHandler({
async start(_ctx, client, input: GetLanguagesInput) {
const handle = client.client.workflow.getHandle(workflowIdForUser(input.userId));
const result = await handle.query(getLanguagesQuery);
return temporalNexus.TemporalOperationResult.sync(result);
},
}),

getLanguage: async (ctx, input: GetLanguageInput) => {
const client = temporalNexus.getClient();
const handle = client.workflow.getHandle(workflowIdForUser(input.userId));
return await handle.query(getLanguageQuery);
},
getLanguage: new temporalNexus.TemporalOperationHandler({
async start(_ctx, client, input: GetLanguageInput) {
const handle = client.client.workflow.getHandle(workflowIdForUser(input.userId));
const result = await handle.query(getLanguageQuery);
return temporalNexus.TemporalOperationResult.sync(result);
},
}),

setLanguage: async (ctx, input: SetLanguageInput) => {
const client = temporalNexus.getClient();
const handle = client.workflow.getHandle(workflowIdForUser(input.userId));
return await handle.executeUpdate(setLanguageUpdate, { args: [input.language] });
},
setLanguage: new temporalNexus.TemporalOperationHandler({
async start(_ctx, client, input: SetLanguageInput) {
const handle = client.getWorkflowHandle(workflowIdForUser(input.userId));
return await handle.update(setLanguageUpdate, { args: [input.language] });
},
}),

approve: async (ctx, input: ApproveInput) => {
const client = temporalNexus.getClient();
const handle = client.workflow.getHandle(workflowIdForUser(input.userId));
await handle.signal(approveSignal);
},
approve: new temporalNexus.TemporalOperationHandler({
async start(_ctx, client, input: ApproveInput) {
const handle = client.getWorkflowHandle(workflowIdForUser(input.userId));
await handle.signal(approveSignal);
return temporalNexus.TemporalOperationResult.sync(undefined);
},
}),
});
19 changes: 12 additions & 7 deletions nexus-messaging/src/ondemandpattern/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,24 @@ The caller workflow:

### Running

Start a Temporal server:
Start a compatible Temporal dev server with Workflow Update callbacks enabled:

```bash
temporal server start-dev
./temporal server start-dev \
--dynamic-config-value history.enableCHASMCallbacks=true \
--dynamic-config-value history.enableUpdateCallbacks=true \
--dynamic-config-value history.enableCHASMSignalBacklinks=true \
--namespace nexus-messaging-handler-namespace \
--namespace nexus-messaging-caller-namespace
```

Create the namespaces and Nexus endpoint:
This sample requires a Temporal dev-server build that supports Workflow Update callbacks. Download the compatible
binary from the [Temporal CLI pre-release instructions](https://docs.temporal.io/standalone-nexus-operation#temporal-cli-support).

```bash
temporal operator namespace create --namespace nexus-messaging-handler-namespace
temporal operator namespace create --namespace nexus-messaging-caller-namespace
Create the Nexus endpoint:

temporal operator nexus endpoint create \
```bash
./temporal operator nexus endpoint create \
--name nexus-messaging-nexus-endpoint \
--target-namespace nexus-messaging-handler-namespace \
--target-task-queue nexus-messaging-handler-task-queue
Expand Down
47 changes: 27 additions & 20 deletions nexus-messaging/src/ondemandpattern/service/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,34 @@ export const nexusRemoteGreetingServiceHandler = nexus.serviceHandler(nexusRemot
},
),

getLanguages: async (ctx, input: GetLanguagesInput) => {
const client = temporalNexus.getClient();
const handle = client.workflow.getHandle(getWorkflowId(input.userId));
return await handle.query(getLanguagesQuery);
},
getLanguages: new temporalNexus.TemporalOperationHandler({
async start(_ctx, client, input: GetLanguagesInput) {
const handle = client.client.workflow.getHandle(getWorkflowId(input.userId));
const result = await handle.query(getLanguagesQuery);
return temporalNexus.TemporalOperationResult.sync(result);
},
}),

getLanguage: async (ctx, input: GetLanguageInput) => {
const client = temporalNexus.getClient();
const handle = client.workflow.getHandle(getWorkflowId(input.userId));
return await handle.query(getLanguageQuery);
},
getLanguage: new temporalNexus.TemporalOperationHandler({
async start(_ctx, client, input: GetLanguageInput) {
const handle = client.client.workflow.getHandle(getWorkflowId(input.userId));
const result = await handle.query(getLanguageQuery);
return temporalNexus.TemporalOperationResult.sync(result);
},
}),

setLanguage: async (ctx, input: SetLanguageInput) => {
const client = temporalNexus.getClient();
const handle = client.workflow.getHandle(getWorkflowId(input.userId));
return await handle.executeUpdate(setLanguageUpdate, { args: [input.language] });
},
setLanguage: new temporalNexus.TemporalOperationHandler({
async start(_ctx, client, input: SetLanguageInput) {
const handle = client.getWorkflowHandle(getWorkflowId(input.userId));
return await handle.update(setLanguageUpdate, { args: [input.language] });
},
}),

approve: async (ctx, input: ApproveInput) => {
const client = temporalNexus.getClient();
const handle = client.workflow.getHandle(getWorkflowId(input.userId));
await handle.signal(approveSignal);
},
approve: new temporalNexus.TemporalOperationHandler({
async start(_ctx, client, input: ApproveInput) {
const handle = client.getWorkflowHandle(getWorkflowId(input.userId));
await handle.signal(approveSignal);
return temporalNexus.TemporalOperationResult.sync(undefined);
},
}),
});