Skip to content

Commit 17adffb

Browse files
committed
Splitting test cases apart
1 parent b6c14f4 commit 17adffb

27 files changed

+480
-204
lines changed
Lines changed: 10 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,16 @@
11
This sample shows how to expose a long-running workflow's queries, updates, and signals as Nexus
2-
operations. The caller interacts only with the Nexus service; the workflow is a private
3-
implementation detail.
2+
operations. There are two self-contained examples, each in its own directory:
43

5-
There are **two caller patterns** that share the same handler workflow (`GreetingWorkflow`):
6-
7-
| | `caller/` (entity pattern) | `caller_remote/` (remote-start pattern) |
4+
| | `callerpattern/` | `ondemandpattern/` |
85
|---|---|---|
9-
| **Who creates the workflow?** | The handler worker starts it on boot | The caller starts it via a `runFromRemote` Nexus operation |
6+
| **Pattern** | Signal an existing workflow | Create and run workflows on demand |
7+
| **Who creates the workflow?** | The handler worker starts it on boot | The caller starts it via a Nexus operation |
108
| **Who knows the workflow ID?** | Only the handler | The caller chooses and passes it in every operation |
11-
| **Nexus service** | `NexusGreetingService` — inputs carry only business data | `NexusRemoteGreetingService` — every input includes a `workflowId` |
12-
| **When to use** | Single shared entity; callers don't need lifecycle control | Caller needs to create and target specific workflow instances |
13-
14-
### Directory structure
15-
16-
- `service/` — shared Nexus service definitions (`NexusGreetingService`, `NexusRemoteGreetingService`) and `Language` enum
17-
- `handler/``GreetingWorkflow` and its implementation, `GreetingActivity`, both Nexus service impls (`NexusGreetingServiceImpl`, `NexusRemoteGreetingServiceImpl`), and the handler worker
18-
- `caller/` — entity-pattern caller (workflow, worker, starter)
19-
- `caller_remote/` — remote-start caller (workflow, worker, starter)
20-
21-
### Running
22-
23-
Start a Temporal server:
24-
25-
```bash
26-
temporal server start-dev
27-
```
28-
Create the namespaces and Nexus endpoint:
29-
30-
```bash
31-
temporal operator namespace create --namespace nexus-messaging-handler-namespace
32-
temporal operator namespace create --namespace nexus-messaging-caller-namespace
33-
34-
temporal operator nexus endpoint create \
35-
--name nexus-messaging-nexus-endpoint \
36-
--target-namespace nexus-messaging-handler-namespace \
37-
--target-task-queue nexus-messaging-handler-task-queue
38-
```
39-
40-
In one terminal, start the handler worker (shared by both patterns):
41-
42-
```bash
43-
./gradlew -q :core:execute -PmainClass=io.temporal.samples.nexus_messaging.handler.HandlerWorker --args="-target-host localhost:7233 -namespace my-target-namespace"
44-
```
45-
46-
#### Entity pattern
47-
48-
In the second terminal, run the caller worker:
49-
50-
```bash
51-
./gradlew -q :core:execute -PmainClass=io.temporal.samples.nexus_messaging.caller.CallerWorker --args="-target-host localhost:7233 -namespace my-caller-namespace"
52-
```
53-
54-
In the third terminal, start the caller workflow:
55-
56-
```bash
57-
./gradlew -q :core:execute -PmainClass=io.temporal.samples.nexus_messaging.caller.CallerStarter --args="-target-host localhost:7233 -namespace my-caller-namespace"
58-
```
59-
60-
Expected output:
61-
62-
```
63-
supported languages: [CHINESE, ENGLISH]
64-
language changed: ENGLISH -> ARABIC
65-
workflow approved
66-
```
67-
68-
#### Remote-start pattern
69-
70-
In a second terminal, run the remote caller worker:
71-
72-
```bash
73-
./gradlew -q :core:execute -PmainClass=io.temporal.samples.nexus_messaging.caller_remote.CallerRemoteWorker --args="-target-host localhost:7233 -namespace my-caller-namespace"
74-
```
75-
76-
In a third terminal, start the remote caller workflow:
77-
78-
```bash
79-
./gradlew -q :core:execute -PmainClass=io.temporal.samples.nexus_messaging.caller_remote.CallerRemoteStarter --args="-target-host localhost:7233 -namespace my-caller-namespace"
80-
```
81-
82-
Expected output:
83-
84-
```
85-
started remote greeting workflow: nexus-messaging-remote-greeting-workflow
86-
supported languages: [CHINESE, ENGLISH]
87-
language changed: ENGLISH -> ARABIC
88-
workflow approved
89-
workflow result: مرحبا بالعالم
90-
```
91-
92-
### How it works
93-
94-
#### The handler (shared by both patterns)
95-
96-
`GreetingWorkflow` is a long-running "entity" workflow that holds the current language and a map of
97-
greetings. It exposes its state through standard Temporal primitives:
98-
99-
- `getLanguages` / `getLanguage``@QueryMethod`s for reading state
100-
- `setLanguage` — an `@UpdateMethod` for switching between already-loaded languages
101-
- `setLanguageUsingActivity` — an `@UpdateMethod` that calls an activity to fetch a greeting for
102-
a language not yet in the map (uses `WorkflowLock` to serialize concurrent activity calls)
103-
- `approve` — a `@SignalMethod` that lets the workflow complete
104-
105-
The workflow waits until approved and all in-flight update handlers have finished, then returns the
106-
greeting in the current language.
107-
108-
Both Nexus service implementations translate incoming Nexus operations into calls against
109-
`GreetingWorkflow` stubs — queries, updates, and signals. The caller never interacts with the
110-
workflow directly.
111-
112-
#### Entity pattern (`caller/` + `NexusGreetingService`)
113-
114-
The handler worker starts a single `GreetingWorkflow` on boot with a fixed workflow ID.
115-
`NexusGreetingServiceImpl` holds that workflow ID in its constructor and routes every operation to
116-
it. The caller's inputs contain only business data (language, name), not workflow IDs.
117-
118-
`CallerWorkflowImpl` creates a `NexusGreetingService` stub and:
119-
1. Queries for supported languages (`getLanguages` — backed by a `@QueryMethod`)
120-
2. Changes the language to Arabic (`setLanguage` — backed by an `@UpdateMethod` that calls an activity)
121-
3. Confirms the change via a second query (`getLanguage`)
122-
4. Approves the workflow (`approve` — backed by a `@SignalMethod`)
123-
124-
#### Remote-start pattern (`caller_remote/` + `NexusRemoteGreetingService`)
125-
126-
No workflow is pre-started. Instead, `NexusRemoteGreetingService` adds a `runFromRemote` operation
127-
that starts a new `GreetingWorkflow` with a caller-chosen workflow ID using
128-
`WorkflowRunOperation`. Every other operation also includes the `workflowId` in its input so that
129-
`NexusRemoteGreetingServiceImpl` can look up the right workflow stub.
9+
| **Nexus service** | `NexusGreetingService` | `NexusRemoteGreetingService` |
13010

131-
`CallerRemoteWorkflowImpl` creates a `NexusRemoteGreetingService` stub and:
132-
1. Starts a remote `GreetingWorkflow` via `runFromRemote` and waits for it to be running
133-
2. Queries, updates, and approves that workflow — same operations as the entity pattern, but each
134-
input carries the workflow ID
135-
3. Waits for the remote workflow to complete and returns its result (the greeting string)
11+
Each directory is fully self-contained with its own `service/`, `handler/`, and caller code. The
12+
`GreetingWorkflow` and `GreetingWorkflowImpl` classes are **identical** between the two — only the
13+
Nexus service interface and its implementation differ. This highlights that the same workflow can be
14+
exposed through Nexus in different ways depending on whether the caller needs lifecycle control.
13615

137-
This pattern is useful when the caller needs to control the lifecycle of individual workflow
138-
instances rather than sharing a single entity.
16+
See each directory's README for running instructions.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
## Entity pattern
2+
3+
The handler worker starts a single `GreetingWorkflow` on boot with a fixed workflow ID.
4+
`NexusGreetingServiceImpl` holds that ID and routes every Nexus operation to it. The caller's
5+
inputs contain only business data — no workflow IDs.
6+
7+
The caller workflow:
8+
1. Queries for supported languages (`getLanguages` — backed by a `@QueryMethod`)
9+
2. Changes the language to Arabic (`setLanguage` — backed by an `@UpdateMethod` that calls an activity)
10+
3. Confirms the change via a second query (`getLanguage`)
11+
4. Approves the workflow (`approve` — backed by a `@SignalMethod`)
12+
13+
### Running
14+
15+
Start a Temporal server:
16+
17+
```bash
18+
temporal server start-dev
19+
```
20+
21+
Create the namespaces and Nexus endpoint:
22+
23+
```bash
24+
temporal operator namespace create --namespace nexus-messaging-handler-namespace
25+
temporal operator namespace create --namespace nexus-messaging-caller-namespace
26+
27+
temporal operator nexus endpoint create \
28+
--name nexus-messaging-nexus-endpoint \
29+
--target-namespace nexus-messaging-handler-namespace \
30+
--target-task-queue nexus-messaging-handler-task-queue
31+
```
32+
33+
In one terminal, start the handler worker:
34+
35+
```bash
36+
./gradlew -q :core:execute -PmainClass=io.temporal.samples.nexus_messaging.callerpattern.handler.HandlerWorker
37+
```
38+
39+
In a second terminal, start the caller worker:
40+
41+
```bash
42+
./gradlew -q :core:execute -PmainClass=io.temporal.samples.nexus_messaging.callerpattern.caller.CallerWorker
43+
```
44+
45+
In a third terminal, start the caller workflow:
46+
47+
```bash
48+
./gradlew -q :core:execute -PmainClass=io.temporal.samples.nexus_messaging.callerpattern.caller.CallerStarter
49+
```
50+
51+
Expected output:
52+
53+
```
54+
Supported languages: [CHINESE, ENGLISH]
55+
Language changed: ENGLISH -> ARABIC
56+
Workflow approved
57+
```

core/src/main/java/io/temporal/samples/nexus_messaging/caller/CallerStarter.java renamed to core/src/main/java/io/temporal/samples/nexus_messaging/callerpattern/caller/CallerStarter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.temporal.samples.nexus_messaging.caller;
1+
package io.temporal.samples.nexus_messaging.callerpattern.caller;
22

33
import io.temporal.client.WorkflowClient;
44
import io.temporal.client.WorkflowClientOptions;

core/src/main/java/io/temporal/samples/nexus_messaging/caller/CallerWorker.java renamed to core/src/main/java/io/temporal/samples/nexus_messaging/callerpattern/caller/CallerWorker.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.temporal.samples.nexus_messaging.caller;
1+
package io.temporal.samples.nexus_messaging.callerpattern.caller;
22

33
import io.temporal.client.WorkflowClient;
44
import io.temporal.client.WorkflowClientOptions;

core/src/main/java/io/temporal/samples/nexus_messaging/caller/CallerWorkflow.java renamed to core/src/main/java/io/temporal/samples/nexus_messaging/callerpattern/caller/CallerWorkflow.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.temporal.samples.nexus_messaging.caller;
1+
package io.temporal.samples.nexus_messaging.callerpattern.caller;
22

33
import io.temporal.workflow.WorkflowInterface;
44
import io.temporal.workflow.WorkflowMethod;

core/src/main/java/io/temporal/samples/nexus_messaging/caller/CallerWorkflowImpl.java renamed to core/src/main/java/io/temporal/samples/nexus_messaging/callerpattern/caller/CallerWorkflowImpl.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
package io.temporal.samples.nexus_messaging.caller;
1+
package io.temporal.samples.nexus_messaging.callerpattern.caller;
22

33
import io.temporal.failure.ApplicationFailure;
4-
import io.temporal.samples.nexus_messaging.callerondemand.CallerRemoteWorkflowImpl;
5-
import io.temporal.samples.nexus_messaging.service.Language;
6-
import io.temporal.samples.nexus_messaging.service.NexusGreetingService;
4+
import io.temporal.samples.nexus_messaging.callerpattern.service.Language;
5+
import io.temporal.samples.nexus_messaging.callerpattern.service.NexusGreetingService;
76
import io.temporal.workflow.NexusOperationOptions;
87
import io.temporal.workflow.NexusServiceOptions;
98
import io.temporal.workflow.Workflow;
@@ -14,7 +13,7 @@
1413

1514
public class CallerWorkflowImpl implements CallerWorkflow {
1615

17-
private static final Logger logger = Workflow.getLogger(CallerRemoteWorkflowImpl.class);
16+
private static final Logger logger = Workflow.getLogger(CallerWorkflowImpl.class);
1817

1918
// The endpoint is configured at the worker level in CallerWorker; only operation options are
2019
// set here.

core/src/main/java/io/temporal/samples/nexus_messaging/handler/GreetingActivity.java renamed to core/src/main/java/io/temporal/samples/nexus_messaging/callerpattern/handler/GreetingActivity.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
package io.temporal.samples.nexus_messaging.handler;
1+
package io.temporal.samples.nexus_messaging.callerpattern.handler;
22

33
import io.temporal.activity.ActivityInterface;
44
import io.temporal.activity.ActivityMethod;
5-
import io.temporal.samples.nexus_messaging.service.Language;
5+
import io.temporal.samples.nexus_messaging.callerpattern.service.Language;
66

77
@ActivityInterface
88
public interface GreetingActivity {

core/src/main/java/io/temporal/samples/nexus_messaging/handler/GreetingActivityImpl.java renamed to core/src/main/java/io/temporal/samples/nexus_messaging/callerpattern/handler/GreetingActivityImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
package io.temporal.samples.nexus_messaging.handler;
1+
package io.temporal.samples.nexus_messaging.callerpattern.handler;
22

3-
import io.temporal.samples.nexus_messaging.service.Language;
3+
import io.temporal.samples.nexus_messaging.callerpattern.service.Language;
44
import java.util.EnumMap;
55
import java.util.Map;
66

core/src/main/java/io/temporal/samples/nexus_messaging/handler/GreetingWorkflow.java renamed to core/src/main/java/io/temporal/samples/nexus_messaging/callerpattern/handler/GreetingWorkflow.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
package io.temporal.samples.nexus_messaging.handler;
1+
package io.temporal.samples.nexus_messaging.callerpattern.handler;
22

33
import com.fasterxml.jackson.annotation.JsonCreator;
44
import com.fasterxml.jackson.annotation.JsonProperty;
5-
import io.temporal.samples.nexus_messaging.service.Language;
6-
import io.temporal.samples.nexus_messaging.service.NexusGreetingService;
5+
import io.temporal.samples.nexus_messaging.callerpattern.service.Language;
6+
import io.temporal.samples.nexus_messaging.callerpattern.service.NexusGreetingService;
77
import io.temporal.workflow.QueryMethod;
88
import io.temporal.workflow.SignalMethod;
99
import io.temporal.workflow.UpdateMethod;

core/src/main/java/io/temporal/samples/nexus_messaging/handler/GreetingWorkflowImpl.java renamed to core/src/main/java/io/temporal/samples/nexus_messaging/callerpattern/handler/GreetingWorkflowImpl.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
package io.temporal.samples.nexus_messaging.handler;
1+
package io.temporal.samples.nexus_messaging.callerpattern.handler;
22

33
import io.temporal.activity.ActivityOptions;
44
import io.temporal.failure.ApplicationFailure;
5-
import io.temporal.samples.nexus_messaging.service.Language;
6-
import io.temporal.samples.nexus_messaging.service.NexusGreetingService;
5+
import io.temporal.samples.nexus_messaging.callerpattern.service.Language;
6+
import io.temporal.samples.nexus_messaging.callerpattern.service.NexusGreetingService;
77
import io.temporal.workflow.Workflow;
88
import java.time.Duration;
99
import java.util.ArrayList;
@@ -82,7 +82,6 @@ public void validateSetLanguage(NexusGreetingService.SetLanguageInput input) {
8282
@Override
8383
public Language setLanguageUsingActivity(NexusGreetingService.SetLanguageInput input) {
8484
if (!greetings.containsKey(input.getLanguage())) {
85-
8685
String greeting = greetingActivity.callGreetingService(input.getLanguage());
8786
if (greeting == null) {
8887
throw ApplicationFailure.newFailure(

0 commit comments

Comments
 (0)