Temporal Nexus - Java SDK Feature Guide
Temporal Java SDK support for Nexus is available in Pre-release.
Use Temporal Nexus to connect Temporal Applications within and across Namespaces using a Nexus Endpoint, a Nexus Service contract, and Nexus Operations.
This page shows how to do the following:
- Run a development Temporal Service with Nexus enabled
- Create caller and handler Namespaces
- Create a Nexus Endpoint to route requests from caller to handler
- Define the Nexus Service contract
- Develop a Nexus Service and Operation handlers
- Develop a caller Workflow that uses a Nexus Service
- Make Nexus calls across Namespaces with a development Server
- Make Nexus calls across Namespaces in Temporal Cloud
Run a development server with Nexus enabled
The first step in working with Temporal Nexus involves starting a Temporal server with Nexus enabled.
Prerequisites:
- Install the latest Temporal CLI
- Install the latest Temporal Java SDK (v1.26.0 or higher)
Start the Temporal Development Server
Start the Temporal Development Server by using the temporal server start-dev
, with system.enableNexus=true
.
The HTTP port is required for Nexus communications.
temporal server start-dev --http-port 7243 --dynamic-config-value system.enableNexus=true
This command automatically starts the Temporal development server, the Web UI, creates the default
Namespace, and uses an in-memory database.
The Temporal Server should be available on localhost:7233
and the Temporal Web UI should be accessible at http://localhost:8233.
Create caller and handler Namespaces
Before setting up Nexus endpoints, create separate Namespaces for the caller and handler.
temporal operator namespace create --namespace my-target-namespace
temporal operator namespace create --namespace my-caller-namespace
The role of my-target-namespace
will be to contain the Operation handler. The role of my-caller-namespace
will be to attempt to call the Operation handler.
We use two namespaces here to demonstrate cross-Namespace Nexus calls.
Create a Nexus Endpoint to route requests from caller to handler
After establishing caller and handler Namespaces, the next step is to create a Nexus Endpoint to route requests.
temporal operator nexus endpoint create \
--name my-nexus-endpoint-name \
--target-namespace my-target-namespace \
--target-task-queue my-handler-task-queue
Define the Nexus Service contract
Defining a clear contract for the Nexus Service is crucial for smooth communication between services.
View the source code in the context of the rest of the application code.
git clone https://github.com/temporalio/samples-java.git
cd samples-java
The Nexus Service contract can be in whatever form works best for your environment. Each Temporal SDK includes and uses a default Data Converter. The default data converter encodes payloads in the following order: Null, Byte array, Protobuf JSON, and JSON. In a polyglot environment, that is where more than one language and SDK is being used to develop a Temporal solution, Protobuf and JSON are common choices. This example uses Java classes serialized into JSON.
In this example, there is a service package that describes the Service and Operation names along with input/output types for caller Workflows to use the Nexus Endpoint.
core/src/main/java/io/temporal/samples/nexus/service/NexusService.java
@Service
public interface NexusService {
enum Language {
EN,
FR,
DE,
ES,
TR
}
class HelloInput {
private final String name;
private final Language language;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public HelloInput(
@JsonProperty("name") String name, @JsonProperty("language") Language language) {
this.name = name;
this.language = language;
}
@JsonProperty("name")
public String getName() {
return name;
}
@JsonProperty("language")
public Language getLanguage() {
return language;
}
}
class HelloOutput {
private final String message;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public HelloOutput(@JsonProperty("message") String message) {
this.message = message;
}
@JsonProperty("message")
public String getMessage() {
return message;
}
}
class EchoInput {
private final String message;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public EchoInput(@JsonProperty("message") String message) {
this.message = message;
}
@JsonProperty("message")
public String getMessage() {
return message;
}
}
class EchoOutput {
private final String message;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public EchoOutput(@JsonProperty("message") String message) {
this.message = message;
}
@JsonProperty("message")
public String getMessage() {
return message;
}
}
@Operation
HelloOutput hello(HelloInput input);
@Operation
EchoOutput echo(EchoInput input);
}
Develop a Nexus Service and Operation handlers
Nexus Operation handlers are typically defined in the same Worker as the underlying Temporal primitives they abstract. Operation handlers can decide if a given Nexus Operation will be synchronous or asynchronous, execute arbitrary code, and invoke underlying Temporal primitives such as a Workflow, Query, Signal, or Update.
The io.temporal.nexus.WorkflowClientOperationHandlers
class has builders to create Nexus Operations:
sync
- Simple synchronous RPC handlers, such as for SignalsfromWorkflowMethod
- Run a Workflow as an asynchronous Nexus Operation
This tutorial starts with a sync
example, and then uses fromWorkflowMethod
to start a handler Workflow from a Nexus Operation.
Develop a Synchronous Nexus Operation handler
The WorkflowClientOperationHandlers.sync
method is for exposing simple RPC handlers.
Its handler function is provided with an SDK client that can be used for signaling, querying, and listing Workflows.
However, implementations are free to make arbitrary calls to other services or databases, or perform computations such as this one:
core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java
// To create a service implementation, annotate the class with @ServiceImpl and provide the
// interface that the service implements. The service implementation class should have methods that
// return OperationHandler that correspond to the operations defined in the service interface.
@ServiceImpl(service = NexusService.class)
public class NexusServiceImpl {
@OperationImpl
public OperationHandler<NexusService.EchoInput, NexusService.EchoOutput> echo() {
// WorkflowClientOperationHandlers.sync is a meant for exposing simple RPC handlers.
return WorkflowClientOperationHandlers.sync(
// The method is provided with an SDK client that can be used for arbitrary calls such as
// signaling, querying,
// and listing workflows but implementations are free to make arbitrary calls to other
// services or databases, or
// perform simple computations such as this one.
(ctx, details, client, input) -> new NexusService.EchoOutput(input.getMessage()));
}
// ...
}