# Cloud profile for Temporal Cloud
[profile.cloud]
address = "your-namespace.a1b2c.tmprl.cloud:7233"
namespace = "your-namespace"
tls_client_cert_data = "your-tls-client-cert-data"
tls_client_key_path = "your-tls-client-key-path"
```

With the connections options defined in the configuration file, use the `LoadClientOptions` function in the `envconfig`
package to create a Temporal Client using the `cloud` profile as follows:

```go {13-17}
package main

	"fmt"
	"log"

	"go.temporal.io/sdk/client"
	"go.temporal.io/sdk/contrib/envconfig"
)

func main() {
	// Replace with the actual path to your TOML file.
	configFilePath := "/Users/yourname/.config/my-app/temporal.toml"

	opts, err := envconfig.LoadClientOptions(envconfig.LoadClientOptionsRequest{
    ConfigFilePath: configFilePath,
    ConfigFileProfile: "cloud",
	})
	if err != nil {
		log.Fatalf("Failed to load client config from custom file: %v", err)
	}

	c, err := client.Dial(opts)
	if err != nil {
		log.Fatalf("Failed to connect using custom config file: %v", err)
	}
	defer c.Close()

	fmt.Printf("✅ Connected using custom config at: %s\n", configFilePath)
}
```

</TabItem>

<TabItem value="env-vars" label="Environment Variables">
The following environment variables are required to connect to Temporal Cloud:

- `TEMPORAL_NAMESPACE`: Your Namespace and Account ID combination in the format `<namespace_id>.<account_id>`.
- `TEMPORAL_ADDRESS`: The gRPC endpoint for your Temporal Cloud Namespace.
- `TEMPORAL_API_KEY`: Your API key value. Required if you are using API key authentication.
- `TEMPORAL_TLS_CLIENT_CERT_DATA` or `TEMPORAL_TLS_CLIENT_CERT_PATH`: Your mTLS client certificate data or file path.
  Required if you are using mTLS authentication.
- `TEMPORAL_TLS_CLIENT_KEY_DATA` or `TEMPORAL_TLS_CLIENT_KEY_PATH`: Your mTLS client private key data or file path.
  Required if you are using mTLS authentication.

Ensure these environment variables exist in your environment before running your Go application.

Import the `envconfig` package to set connection options for the Temporal Client using environment variables. The
`MustLoadDefaultClientOptions` function will automatically load all environment variables. For a list of all available
environment variables and their default values, refer to [Environment Configuration](../environment-configuration).

For example, the following code snippet loads all environment variables and creates a Temporal Client with the options
specified in those variables. If you have defined a configuration file at either the default location
(`~/.config/temporalio/temporal.toml`) or a custom location specified by the `TEMPORAL_CONFIG_FILE` environment
variable, this will also load the default profile in the configuration file. However, any options set via environment
variables will take precedence.

```go {13}
package main

	"fmt"
	"log"

	"go.temporal.io/sdk/client"
	"go.temporal.io/sdk/contrib/envconfig"
)

func main() {
	// Loads the "default" profile from the standard location and environment variables.
	c, err := client.Dial(envconfig.MustLoadDefaultClientOptions())
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}
	defer c.Close()

	fmt.Printf("✅ Connected to Temporal Service")
}
```

</TabItem>

<TabItem value="code" label="Code">

You can also provide connections options in your Go code directly. When instantiating a Temporal `client` in your
Temporal Go SDK code, provide the following `clientOptions`:

```go
clientOptions := client.Options{
    HostPort: <endpoint>,
    Namespace: <namespace_id>.<account_id>,
    ConnectionOptions: client.ConnectionOptions{TLS: &tls.Config{}},
    Credentials: client.NewAPIKeyStaticCredentials(apiKey),
}
c, err := client.Dial(clientOptions)
```

To update an API key, use the Go `context` object:

```go
// Assuming client Credentials created with
var myKey string
creds := client.NewAPIKeyDynamicCredentials(
    func(context.Context) (string, error) { return myKey, nil })
// Update by replacing
myKey = myKeyUpdated
```

You can use a combination of environment variables, configuration files, and code to set connection options. For
example, you can load a base configuration from environment variables or a configuration file, and then override
specific options in code.

For example, the following code snippet loads the base configuration from environment variables and the default profile
with `envconfig.MustLoadDefaultClientOptions()`. It then overrides the `HostPort` and `Namespace` options
programmatically. Refer to
[Client Options type in the Go SDK](https://pkg.go.dev/go.temporal.io/sdk/internal#ClientOptions) for a list of all
available connection options you can override.

```go
package main

	"fmt"
	"log"

	"go.temporal.io/sdk/client"
	"go.temporal.io/sdk/contrib/envconfig"
)

func main() {
	// Load the base configuration (e.g., from the default profile).
	opts := envconfig.MustLoadDefaultClientOptions()

	// Apply overrides programmatically.
	opts.HostPort = "localhost:7233"
	opts.Namespace = "test-namespace"

	c, err := client.Dial(opts)
	if err != nil {
		log.Fatalf("Failed to connect with overridden options: %v", err)
	}
	defer c.Close()

	fmt.Printf("✅ Connected with overridden config to: %s in namespace: %s\n", opts.HostPort, opts.Namespace)
}
```

<details>
<summary>v1.26.0 to v1.32.x </summary>

Create an initial connection:

```go
clientOptions := client.Options{
    HostPort: <endpoint>,
    Namespace: <namespace_id>.<account_id>,
    ConnectionOptions: client.ConnectionOptions{
        TLS: &tls.Config{},
        DialOptions: []grpc.DialOption{
            grpc.WithUnaryInterceptor(
                func(ctx context.Context, method string, req any, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
                    return invoker(
                        metadata.AppendToOutgoingContext(ctx, "temporal-namespace", <namespace_id>.<account_id>),
                        method,
                        req,
                        reply,
                        cc,
                        opts...,
                    )
                },
            ),
        },
    },
    Credentials: client.NewAPIKeyStaticCredentials(apiKey),
}
c, err := client.Dial(clientOptions)
if err != nil {
  log.Fatalf("error creating temporal client: %v", err)
}
```

Update an API key:

```go
// Assuming client Credentials created with
var myKey string
creds := client.NewAPIKeyDynamicCredentials(
    func(context.Context) (string, error) { return myKey, nil })
// Just update by replacing
myKey = myKeyUpdated
```

</details>

<details>
<summary>pre v1.26.0</summary>

Create an initial connection:

```go
// Create headers provider
type APIKeyProvider struct {
    APIKey string
    Namespace string
}

func (a *APIKeyProvider) GetHeaders(context.Context) (map[string]string, error) {
    return map[string]string{"Authorization": "Bearer " + a.APIKey, "temporal-namespace": a.Namespace}, nil
}

// Use headers provider
apiKeyProvider := &APIKeyProvider{APIKey: <APIKey>, Namespace: <namespace_id>.<account_id>}
c, err := client.Dial(client.Options{
    HostPort: <endpoint>,
    Namespace: <namespace_id>.<account_id>,
    HeadersProvider: apiKeyProvider,
    ConnectionOptions: client.ConnectionOptions{TLS: &tls.Config{
    }},
})
```

Update an API key:

```go
apiKeyProvider.APIKey = myKeyUpdated
```

</details>

</TabItem>

</Tabs>

## Start Workflow Execution {#start-workflow-execution}

**How to start a Workflow Execution using the Go SDK**

[Workflow Execution](/workflow-execution) semantics rely on several parameters—that is, to start a Workflow Execution
you must supply a Task Queue that will be used for the Tasks (one that a Worker is polling), the Workflow Type,
language-specific contextual data, and Workflow Function parameters.

In the examples below, all Workflow Executions are started using a Temporal Client. To spawn Workflow Executions from
within another Workflow Execution, use either the [Child Workflow](/develop/go/child-workflows) or External Workflow
APIs.

See the [Customize Workflow Type](/develop/go/core-application#customize-workflow-type) section to see how to customize
the name of the Workflow Type.

A request to spawn a Workflow Execution causes the Temporal Service to create the first Event
([WorkflowExecutionStarted](/references/events#workflowexecutionstarted)) in the Workflow Execution Event History. The
Temporal Service then creates the first Workflow Task, resulting in the first
[WorkflowTaskScheduled](/references/events#workflowtaskscheduled) Event.

To spawn a [Workflow Execution](/workflow-execution), use the `ExecuteWorkflow()` method on the Go SDK
[`Client`](https://pkg.go.dev/go.temporal.io/sdk/client#Client).

The `ExecuteWorkflow()` API call requires an instance of [`context.Context`](https://pkg.go.dev/context#Context), an
instance of [`StartWorkflowOptions`](https://pkg.go.dev/go.temporal.io/sdk/client#StartWorkflowOptions), a Workflow Type
name, and all variables to be passed to the Workflow Execution. The `ExecuteWorkflow()` call returns a Future, which can
be used to get the result of the Workflow Execution.

```go
package main

  // ...

  "go.temporal.io/sdk/client"
)

func main() {
  temporalClient, err := client.Dial(client.Options{})
  if err != nil {
    // ...
  }
  defer temporalClient.Close()
  // ...
  workflowOptions := client.StartWorkflowOptions{
    // ...
  }
  workflowRun, err := temporalClient.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition, param)
  if err != nil {
    // ...
  }
  // ...
}

func YourWorkflowDefinition(ctx workflow.Context, param YourWorkflowParam) (YourWorkflowResponse, error) {
  // ...
}
```

If the invocation process has access to the function directly, then the Workflow Type name parameter can be passed as if
the function name were a variable, without quotations.

```go
workflowRun, err := temporalClient.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition, param)
```

If the invocation process does not have direct access to the statically defined Workflow Definition, for example, if the
Workflow Definition is in an un-importable package, or it is written in a completely different language, then the
Workflow Type can be provided as a `string`.

```go
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, "YourWorkflowDefinition", param)
```

### Set Workflow Task Queue {#set-task-queue}

**How to set a Workflow's Task Queue using the Go SDK**

In most SDKs, the only Workflow Option that must be set is the name of the [Task Queue](/task-queue).

For any code to execute, a Worker Process must be running that contains a Worker Entity that is polling the same Task
Queue name.

Create an instance of
[`StartWorkflowOptions`](https://pkg.go.dev/go.temporal.io/sdk@v1.10.0/client#StartWorkflowOptions) from the
`go.temporal.io/sdk/client` package, set the `TaskQueue` field, and pass the instance to the `ExecuteWorkflow` call.

- Type: `string`
- Default: None, this is a required field to be set by the developer

```go
workflowOptions := client.StartWorkflowOptions{
  // ...
  TaskQueue: "your-task-queue",
  // ...
}
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
  // ...
}
```

You can configure Task Queues that are host-specific, Worker-specific or Workflow-specific to distribute your
application load. For more information, refer to
[Task Queues Processing Tuning](/develop/worker-performance#task-queues-processing-tuning) and
[Worker Versioning](https://docs.temporal.io/worker-versioning).

### Set custom Workflow Id {#workflow-id}

**How to set a custom Workflow Id using the Go SDK**

Although it is not required, we recommend providing your own
[Workflow Id](/workflow-execution/workflowid-runid#workflow-id) that maps to a business process or business entity
identifier, such as an order identifier or customer identifier.

Create an instance of
[`StartWorkflowOptions`](https://pkg.go.dev/go.temporal.io/sdk@v1.10.0/client#StartWorkflowOptions) from the
`go.temporal.io/sdk/client` package, set the `ID` field, and pass the instance to the `ExecuteWorkflow` call.

- Type: `string`
- Default: System generated UUID

```go
workflowOptions := client.StartWorkflowOptions{
  // ...
  ID: "Your-Custom-Workflow-Id",
  // ...
}
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
  // ...
}
```

### Go StartWorkflowOptions reference {#workflow-options-reference}

Create an instance of
[`StartWorkflowOptions`](https://pkg.go.dev/go.temporal.io/sdk@v1.10.0/client#StartWorkflowOptions) from the
`go.temporal.io/sdk/client` package, and pass the instance to the `ExecuteWorkflow` call.

The following fields are available:

| Field                                                                                   | Required | Type                                                                                            |
| --------------------------------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------- |
| [`ID`](#id)                                                                             | No       | `string`                                                                                        |
| [`TaskQueue`](#taskqueue)                                                               | **Yes**  | `string`                                                                                        |
| [`WorkflowExecutionTimeout`](#workflowexecutiontimeout)                                 | No       | `time.Duration`                                                                                 |
| [`WorkflowRunTimeout`](#workflowruntimeout)                                             | No       | `time.Duration`                                                                                 |
| [`WorkflowTaskTimeout`](#workflowtasktimeout)                                           | No       | `time.Duration`                                                                                 |
| [`WorkflowIDReusePolicy`](#workflowidreusepolicy)                                       | No       | [`WorkflowIdReusePolicy`](https://pkg.go.dev/go.temporal.io/api/enums/v1#WorkflowIdReusePolicy) |
| [`WorkflowExecutionErrorWhenAlreadyStarted`](#workflowexecutionerrorwhenalreadystarted) | No       | `bool`                                                                                          |
| [`RetryPolicy`](#retrypolicy)                                                           | No       | [`RetryPolicy`](https://pkg.go.dev/go.temporal.io/sdk/temporal#RetryPolicy)                     |
| [`CronSchedule`](#cronschedule)                                                         | No       | `string`                                                                                        |
| [`Memo`](#memo)                                                                         | No       | `map[string]interface{}`                                                                        |
| [`SearchAttributes`](#searchattributes)                                                 | No       | `map[string]interface{}`                                                                        |

#### ID

Although it is not required, we recommend providing your own
[Workflow Id](/workflow-execution/workflowid-runid#workflow-id)that maps to a business process or business entity
identifier, such as an order identifier or customer identifier.

Create an instance of [StartWorkflowOptions](https://pkg.go.dev/go.temporal.io/sdk@v1.10.0/client#StartWorkflowOptions)
from the `go.temporal.io/sdk/client` package, set the `ID` field, and pass the instance to the `ExecuteWorkflow` call.

- Type: `string`
- Default: System generated UUID

```go
workflowOptions := client.StartWorkflowOptions{
  // ...
  ID: "Your-Custom-Workflow-Id",
  // ...
}
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
  // ...
}
```

#### TaskQueue

Create an instance of [StartWorkflowOptions](https://pkg.go.dev/go.temporal.io/sdk@v1.10.0/client#StartWorkflowOptions)
from the `go.temporal.io/sdk/client` package, set the `TaskQueue` field, and pass the instance to the `ExecuteWorkflow`
call.

- Type: `string`
- Default: None; this is a required field to be set by the developer

```go
workflowOptions := client.StartWorkflowOptions{
  // ...
  TaskQueue: "your-task-queue",
  // ...
}
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
  // ...
}
```

#### WorkflowExecutionTimeout

Create an instance of [StartWorkflowOptions](https://pkg.go.dev/go.temporal.io/sdk/client#StartWorkflowOptions) from the
`go.temporal.io/sdk/client` package, set the `WorkflowExecutionTimeout` field, and pass the instance to the
`ExecuteWorkflow` call.

- Type: `time.Duration`
- Default: Unlimited

```go
workflowOptions := client.StartWorkflowOptions{
  // ...
  WorkflowExecutionTimeout: time.Hours * 24 * 365 * 10,
  // ...
}
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
  // ...
}
```

#### WorkflowRunTimeout

Create an instance of [StartWorkflowOptions](https://pkg.go.dev/go.temporal.io/sdk/client#StartWorkflowOptions) from the
`go.temporal.io/sdk/client` package, set the `WorkflowRunTimeout` field, and pass the instance to the `ExecuteWorkflow`
call.

- Type: `time.Duration`
- Default: Same as [`WorkflowExecutionTimeout`](#workflowexecutiontimeout)

```go
workflowOptions := client.StartWorkflowOptions{
  WorkflowRunTimeout: time.Hours * 24 * 365 * 10,
  // ...
}
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
  // ...
}
```

#### WorkflowTaskTimeout

Create an instance of [StartWorkflowOptions](https://pkg.go.dev/go.temporal.io/sdk/client#StartWorkflowOptions) from the
`go.temporal.io/sdk/client` package, set the `WorkflowTaskTimeout` field, and pass the instance to the `ExecuteWorkflow`
call.

- Type: `time.Duration`
- Default: `time.Seconds * 10`

```go
workflowOptions := client.StartWorkflowOptions{
  WorkflowTaskTimeout: time.Second * 10,
  //...
}
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
  // ...
}
```

#### WorkflowIDReusePolicy

- Type: [WorkflowIdReusePolicy](https://pkg.go.dev/go.temporal.io/api/enums/v1#WorkflowIdReusePolicy)
- Default: `enums.WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE`

Set a value from the `go.temporal.io/api/enums/v1` package.

```go
workflowOptions := client.StartWorkflowOptions{
  WorkflowIdReusePolicy: enums.WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE,
  // ...
}
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
  // ...
}
```

#### WorkflowExecutionErrorWhenAlreadyStarted

- Type: `bool`
- Default: `false`

```go
workflowOptions := client.StartWorkflowOptions{
  WorkflowExecutionErrorWhenAlreadyStarted: false,
  // ...
}
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
  // ...
}
```

#### RetryPolicy

Create an instance of a [RetryPolicy](https://pkg.go.dev/go.temporal.io/sdk/temporal#RetryPolicy) from the
`go.temporal.io/sdk/temporal` package and provide it as the value to the `RetryPolicy` field of the instance of
`StartWorkflowOptions`.

- Type: [RetryPolicy](https://pkg.go.dev/go.temporal.io/sdk/temporal#RetryPolicy)
- Default: None

```go
retrypolicy := &temporal.RetryPolicy{
  InitialInterval:    time.Second,
  BackoffCoefficient: 2.0,
  MaximumInterval:    time.Second * 100,
}
workflowOptions := client.StartWorkflowOptions{
  RetryPolicy: retrypolicy,
  // ...
}
workflowRun, err := temporalClient.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
  // ...
}
```

#### CronSchedule

- Type: `string`
- Default: None

```go
workflowOptions := client.StartWorkflowOptions{
  CronSchedule: "15 8 * * *",
  // ...
}
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
  // ...
}
```

[Sample](https://github.com/temporalio/samples-go/tree/master/cron)

#### Memo

- Type: `map[string]interface{}`
- Default: Empty

```go
workflowOptions := client.StartWorkflowOptions{
  Memo: map[string]interface{}{
    "description": "Test search attributes workflow",
  },
  // ...
}
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
  // ...
}
```

#### SearchAttributes

**How to set Workflow Execution Search Attributes in Go**

- Type: `map[string]interface{}`
- Default: Empty.

These are the corresponding [Search Attribute value types](/search-attribute#supported-types) in Go:

- Keyword = string
- Int = int64
- Double = float64
- Bool = bool
- Datetime = time.Time
- Text = string

```go
searchAttributes := map[string]interface{}{
  "CustomIntField": 1,
  "MiscData": "yellow",
}
workflowOptions := client.StartWorkflowOptions{
  SearchAttributes: searchAttributes,
  // ...
}
workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition)
if err != nil {
  // ...
}
```

### Get Workflow results {#get-workflow-results}

**How to get the results of a Workflow Execution using the Go SDK**

If the call to start a Workflow Execution is successful, you will gain access to the Workflow Execution's Run Id.

The Workflow Id, Run Id, and Namespace may be used to uniquely identify a Workflow Execution in the system and get its
result.

It's possible to both block progress on the result (synchronous execution) or get the result at some other point in time
(asynchronous execution).

In the Temporal Platform, it's also acceptable to use Queries as the preferred method for accessing the state and
results of Workflow Executions.

The `ExecuteWorkflow` call returns an instance of
[`WorkflowRun`](https://pkg.go.dev/go.temporal.io/sdk/client#WorkflowRun), which is the `workflowRun` variable in the
following line.

```go
 workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, app.YourWorkflowDefinition, param)
 if err != nil {
   // ...
 }
 // ...
}
```

The instance of `WorkflowRun` has the following three methods:

- `GetWorkflowID()`: Returns the Workflow Id of the invoked Workflow Execution.
- `GetRunID()`: Always returns the Run Id of the initial Run (See [Continue As New](#)) in the series of Runs that make
  up the full Workflow Execution.
- `Get`: Takes a pointer as a parameter and populates the associated variable with the Workflow Execution result.

To wait on the result of Workflow Execution in the same process that invoked it, call `Get()` on the instance of
`WorkflowRun` that is returned by the `ExecuteWorkflow()` call.

```go
 workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, YourWorkflowDefinition, param)
 if err != nil {
   // ...
 }
 var result YourWorkflowResponse
 err = workflowRun.Get(context.Background(), &result)
 if err != nil {
     // ...
 }
 // ...
}
```

However, the result of a Workflow Execution can be obtained from a completely different process. All that is needed is
the [Workflow Id](#). (A [Run Id](#) is optional if more than one closed Workflow Execution has the same Workflow Id.)
The result of the Workflow Execution is available for as long as the Workflow Execution Event History remains in the
system.

{/* TODO (See [How long do Workflow Execution Histories persist](#)). */}

Call the `GetWorkflow()` method on an instance of the Go SDK Client and pass it the Workflow Id used to spawn the
Workflow Execution. Then call the `Get()` method on the instance of `WorkflowRun` that is returned, passing it a pointer
to populate the result.

```go
 // ...
 workflowID := "Your-Custom-Workflow-Id"
 workflowRun := c.GetWorkflow(context.Background, workflowID)

 var result YourWorkflowResponse
 err = workflowRun.Get(context.Background(), &result)
 if err != nil {
     // ...
 }
 // ...
```

**Get last completion result**

In the case of a [Temporal Cron Job](/cron-job), you might need to get the result of the previous Workflow Run and use
it in the current Workflow Run.

To do this, use the [`HasLastCompletionResult`](https://pkg.go.dev/go.temporal.io/sdk/workflow#HasLastCompletionResult)
and [`GetLastCompletionResult`](https://pkg.go.dev/go.temporal.io/sdk/workflow#GetLastCompletionResult) APIs, available
from the [`go.temporal.io/sdk/workflow`](https://pkg.go.dev/go.temporal.io/sdk/workflow) package, directly in your
Workflow code.

```go
type CronResult struct {
 Count int
}

func YourCronWorkflowDefinition(ctx workflow.Context) (CronResult, error) {
 count := 1

 if workflow.HasLastCompletionResult(ctx) {
   var lastResult CronResult
   if err := workflow.GetLastCompletionResult(ctx, &lastResult); err == nil {
     count = count + lastResult.Count
   }
 }

 newResult := CronResult {
   Count: count,
 }
 return newResult, nil
}
```

This will work even if one of the cron Workflow Runs fails. The next Workflow Run gets the result of the last
successfully Completed Workflow Run.

---

## Temporal Nexus - Go SDK Feature Guide

:::tip SUPPORT, STABILITY, and DEPENDENCY INFO

Temporal Go SDK support for Nexus is now [Generally Available](/evaluate/development-production-features/release-stages#general-availability).

:::

Use [Temporal Nexus](/evaluate/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](#run-the-temporal-nexus-development-server)
- [Create caller and handler Namespaces](#create-caller-handler-namespaces)
- [Create a Nexus Endpoint to route requests from caller to handler](#create-nexus-endpoint)
- [Define the Nexus Service contract](#define-nexus-service-contract)
- [Develop a Nexus Service and Operation handlers](#develop-nexus-service-operation-handlers)
- [Develop a caller Workflow that uses a Nexus Service](#develop-caller-workflow-nexus-service)
- [Make Nexus calls across Namespaces with a development Server](#nexus-calls-across-namespaces-dev-server)
- [Make Nexus calls across Namespaces in Temporal Cloud](#nexus-calls-across-namespaces-temporal-cloud)

:::note

This documentation uses source code derived from the [Go Nexus sample](https://github.com/temporalio/samples-go/tree/main/nexus).

:::

## Run the Temporal Development Server with Nexus enabled {#run-the-temporal-nexus-development-server}

Prerequisites:

- [Install the latest Temporal CLI](https://docs.temporal.io/develop/go/core-application#run-a-development-server) (v1.3.0 or higher recommended)
- [Install the latest Temporal Go SDK](https://docs.temporal.io/develop/go/core-application#install-a-temporal-sdk)
  (v1.33.0 or higher recommended)

The first step in working with Temporal Nexus involves starting a Temporal server with Nexus enabled.

```
temporal server start-dev
```

This command automatically starts the Temporal development server with the Web UI, and creates the `default` Namespace. It uses an in-memory database, so do not use it for real use cases.

The Temporal Web UI should now be accessible at [http://localhost:8233](http://localhost:8233), and the Temporal Server should now be available for client connections on `localhost:7233`.

## Create caller and handler Namespaces {#create-caller-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
```

`my-target-namespace` will contain the Nexus Operation handler, and we will use a Workflow in `my-caller-namespace` to call that Operation handler.
We use different namespaces to demonstrate cross-Namespace Nexus calls.

## Create a Nexus Endpoint to route requests from caller to handler {#create-nexus-endpoint}

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
```

You can also use the Web UI to create the Namespaces and Nexus endpoint.

## Define the Nexus Service contract {#define-nexus-service-contract}

Defining a clear contract for the Nexus Service is crucial for smooth communication.

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.

Each [Temporal SDK includes and uses a default Data Converter](https://docs.temporal.io/dataconversion).
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 native Go types.

<!--SNIPSTART samples-go-nexus-service {"selectedLines": ["2-13"]}-->
[nexus/service/api.go](https://github.com/temporalio/samples-go/blob/main/nexus/service/api.go)
```go
// ...

const HelloServiceName = "my-hello-service"

// Echo operation
const EchoOperationName = "echo"

type EchoInput struct {
	Message string
}

type EchoOutput EchoInput

```
<!--SNIPEND-->

## Develop a Nexus Service and Operation handlers {#develop-nexus-service-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.
They can execute arbitrary code, and invoke underlying Temporal primitives such as a Workflow, Query, Signal, or Update.

The `temporalnexus` package has builders to create Nexus Operations and other helpers for authoring Operation handlers:

- `NewWorkflowRunOperation` \- Run a Workflow as an asynchronous Nexus Operation
- `GetClient` \- Get the Temporal Client that the Worker was initialized with for synchronous handlers backed by
  Temporal primitives such as Signals and Queries

This tutorial starts with a sync Operation handler example using the `nexus.NewSyncOperation` method, and then shows how to create an async Operation handler that uses `NewWorkflowRunOperation` to start a handler Workflow from a Nexus Operation.

### Develop a Synchronous Nexus Operation handler

The `nexus.NewSyncOperation` builder function is for exposing simple RPC handlers.
Typically to use SDK client, which is obtained via `temporalnexus.GetClient(ctx)`, 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:

<!--SNIPSTART samples-go-nexus-handler {"selectedLines": ["2-23"]}-->
[nexus/handler/app.go](https://github.com/temporalio/samples-go/blob/main/nexus/handler/app.go)
```go
// ...

	"context"
	"fmt"

	"github.com/nexus-rpc/sdk-go/nexus"

	"go.temporal.io/sdk/client"
	"go.temporal.io/sdk/temporalnexus"
	"go.temporal.io/sdk/workflow"

	"github.com/temporalio/samples-go/nexus/service"
)

// NewSyncOperation is a meant for exposing simple RPC handlers.
var EchoOperation = nexus.NewSyncOperation(service.EchoOperationName, func(ctx context.Context, input service.EchoInput, options nexus.StartOperationOptions) (service.EchoOutput, error) {
	// Use temporalnexus.GetClient to get the client that the worker was initialized with to perform client calls
	// such as signaling, querying, and listing workflows. Implementations are free to make arbitrary calls to other
	// services or databases, or perform simple computations such as this one.
	return service.EchoOutput(input), nil
})

```
<!--SNIPEND-->

### Develop an Asynchronous Nexus Operation handler to start a Workflow

Use the `NewWorkflowRunOperation` constructor, which is the easiest way to expose a Workflow as an operation.
See alternatives [here](https://pkg.go.dev/go.temporal.io/sdk/temporalnexus).

<!--SNIPSTART samples-go-nexus-handler {"selectedLines": ["26-35"]}-->
[nexus/handler/app.go](https://github.com/temporalio/samples-go/blob/main/nexus/handler/app.go)
```go
// ...
var HelloOperation = temporalnexus.NewWorkflowRunOperation(service.HelloOperationName, HelloHandlerWorkflow, func(ctx context.Context, input service.HelloInput, options nexus.StartOperationOptions) (client.StartWorkflowOptions, error) {
	return client.StartWorkflowOptions{
		// Workflow IDs should typically be business meaningful IDs and are used to dedupe workflow starts.
		// For this example, we're using the request ID allocated by Temporal when the caller workflow schedules
		// the operation, this ID is guaranteed to be stable across retries of this operation.
		ID: options.RequestID,
		// Task queue defaults to the task queue this operation is handled on.
	}, nil
})

```
<!--SNIPEND-->

Workflow IDs should typically be business-meaningful IDs and are used to dedupe Workflow starts.
For the `HelloOperation`, `input.ID` is passed as part of the Nexus Service contract.

:::tip RESOURCES

[Attach multiple Nexus callers to a handler Workflow](/nexus/operations#attaching-multiple-nexus-callers) with a Conflict-Policy of Use-Existing.

:::

#### Map a Nexus Operation input to multiple Workflow arguments

A Nexus Operation can only take one input parameter. If you want a Nexus Operation to start a Workflow that takes multiple arguments use
`NewWorkflowRunOperationWithOptions` or `MustNewWorkflowRunOperationWithOptions`.

<!--SNIPSTART samples-go-nexus-handler-multiargs-->
[nexus-multiple-arguments/handler/app.go](https://github.com/temporalio/samples-go/blob/main/nexus-multiple-arguments/handler/app.go)
```go
var HelloOperation = temporalnexus.MustNewWorkflowRunOperationWithOptions(temporalnexus.WorkflowRunOperationOptions[service.HelloInput, service.HelloOutput]{
	Name: service.HelloOperationName,
	Handler: func(ctx context.Context, input service.HelloInput, options nexus.StartOperationOptions) (temporalnexus.WorkflowHandle[service.HelloOutput], error) {
		return temporalnexus.ExecuteUntypedWorkflow[service.HelloOutput](
			ctx,
			options,
			client.StartWorkflowOptions{
				// Workflow IDs should typically be business meaningful IDs and are used to dedupe workflow starts.
				// For this example, we're using the request ID allocated by Temporal when the caller workflow schedules
				// the operation, this ID is guaranteed to be stable across retries of this operation.
				ID: options.RequestID,
			},
			HelloHandlerWorkflow,
			input.Name,
			input.Language,
		)
	},
})

```
<!--SNIPEND-->

### Register a Nexus Service in a Worker

After developing an asynchronous Nexus Operation handler to start a Workflow, the next step is to register a Nexus Service in a Worker.

<!--SNIPSTART samples-go-nexus-handler-worker-->
[nexus/handler/worker/main.go](https://github.com/temporalio/samples-go/blob/main/nexus/handler/worker/main.go)
```go
package main

	"log"
	"os"

	"go.temporal.io/sdk/client"
	"go.temporal.io/sdk/worker"

	"github.com/nexus-rpc/sdk-go/nexus"
	"github.com/temporalio/samples-go/nexus/handler"
	"github.com/temporalio/samples-go/nexus/options"
	"github.com/temporalio/samples-go/nexus/service"
)

const (
	taskQueue = "my-handler-task-queue"
)

func main() {
	// The client and worker are heavyweight objects that should be created once per process.
	clientOptions, err := options.ParseClientOptionFlags(os.Args[1:])
	if err != nil {
		log.Fatalf("Invalid arguments: %v", err)
	}
	c, err := client.Dial(clientOptions)
	if err != nil {
		log.Fatalln("Unable to create client", err)
	}
	defer c.Close()

	w := worker.New(c, taskQueue, worker.Options{})
	service := nexus.NewService(service.HelloServiceName)
	err = service.Register(handler.EchoOperation, handler.HelloOperation)
	if err != nil {
		log.Fatalln("Unable to register operations", err)
	}
	w.RegisterNexusService(service)
	w.RegisterWorkflow(handler.HelloHandlerWorkflow)

	err = w.Run(worker.InterruptCh())
	if err != nil {
		log.Fatalln("Unable to start worker", err)
	}
}
```
<!--SNIPEND-->

## Develop a caller Workflow that uses the Nexus Service {#develop-caller-workflow-nexus-service}

Import the Service API package that has the necessary service and operation names and input/output types to execute a Nexus Operation from the caller Workflow:

<!--SNIPSTART samples-go-nexus-caller-workflow-->
[nexus/caller/workflows.go](https://github.com/temporalio/samples-go/blob/main/nexus/caller/workflows.go)
```go
package caller

	"github.com/temporalio/samples-go/nexus/service"
	"go.temporal.io/sdk/workflow"
)

const (
	TaskQueue    = "my-caller-workflow-task-queue"
	endpointName = "my-nexus-endpoint-name"
)

func EchoCallerWorkflow(ctx workflow.Context, message string) (string, error) {
	c := workflow.NewNexusClient(endpointName, service.HelloServiceName)

	fut := c.ExecuteOperation(ctx, service.EchoOperationName, service.EchoInput{Message: message}, workflow.NexusOperationOptions{})

	var res service.EchoOutput
	if err := fut.Get(ctx, &res); err != nil {
		return "", err
	}

	return res.Message, nil
}

func HelloCallerWorkflow(ctx workflow.Context, name string, language service.Language) (string, error) {
	c := workflow.NewNexusClient(endpointName, service.HelloServiceName)

	fut := c.ExecuteOperation(ctx, service.HelloOperationName, service.HelloInput{Name: name, Language: language}, workflow.NexusOperationOptions{})
	var res service.HelloOutput

	// Optionally wait for the operation to be started. NexusOperationExecution will contain the operation token in
	// case this operation is asynchronous, which is a handle that can be used to perform additional actions like
	// cancelling an operation.
	var exec workflow.NexusOperationExecution
	if err := fut.GetNexusOperationExecution().Get(ctx, &exec); err != nil {
		return "", err
	}
	if err := fut.Get(ctx, &res); err != nil {
		return "", err
	}

	return res.Message, nil
}

```
<!--SNIPEND-->

### Register the caller Workflow in a Worker

After developing the caller Workflow, the next step is to register it with a Worker.

<!--SNIPSTART samples-go-nexus-caller-worker-->
[nexus/caller/worker/main.go](https://github.com/temporalio/samples-go/blob/main/nexus/caller/worker/main.go)
```go
package main

	"log"
	"os"

	"github.com/temporalio/samples-go/nexus/caller"
	"github.com/temporalio/samples-go/nexus/options"

	"go.temporal.io/sdk/client"
	"go.temporal.io/sdk/worker"
)

func main() {
	// The client and worker are heavyweight objects that should be created once per process.
	clientOptions, err := options.ParseClientOptionFlags(os.Args[1:])
	if err != nil {
		log.Fatalf("Invalid arguments: %v", err)
	}
	c, err := client.Dial(clientOptions)
	if err != nil {
		log.Fatalln("Unable to create client", err)
	}
	defer c.Close()

	w := worker.New(c, caller.TaskQueue, worker.Options{})

	w.RegisterWorkflow(caller.EchoCallerWorkflow)
	w.RegisterWorkflow(caller.HelloCallerWorkflow)

	err = w.Run(worker.InterruptCh())
	if err != nil {
		log.Fatalln("Unable to start worker", err)
	}
}
```
<!--SNIPEND-->

### Develop a starter to start the caller Workflow

To initiate the caller Workflow, a starter program is required.

<!--SNIPSTART samples-go-nexus-caller-starter-->
[nexus/caller/starter/main.go](https://github.com/temporalio/samples-go/blob/main/nexus/caller/starter/main.go)
```go
package main

	"context"
	"log"
	"os"
	"time"

	"go.temporal.io/sdk/client"

	"github.com/temporalio/samples-go/nexus/caller"
	"github.com/temporalio/samples-go/nexus/options"
	"github.com/temporalio/samples-go/nexus/service"
)

func main() {
	clientOptions, err := options.ParseClientOptionFlags(os.Args[1:])
	if err != nil {
		log.Fatalf("Invalid arguments: %v", err)
	}
	c, err := client.Dial(clientOptions)
	if err != nil {
		log.Fatalln("Unable to create client", err)
	}
	defer c.Close()
	runWorkflow(c, caller.EchoCallerWorkflow, "Nexus Echo 👋")
	runWorkflow(c, caller.HelloCallerWorkflow, "Nexus", service.ES)
}

func runWorkflow(c client.Client, workflow interface{}, args ...interface{}) {
	ctx := context.Background()
	workflowOptions := client.StartWorkflowOptions{
		ID:        "nexus_hello_caller_workflow_" + time.Now().Format("20060102150405"),
		TaskQueue: caller.TaskQueue,
	}

	wr, err := c.ExecuteWorkflow(ctx, workflowOptions, workflow, args...)
	if err != nil {
		log.Fatalln("Unable to execute workflow", err)
	}
	log.Println("Started workflow", "WorkflowID", wr.GetID(), "RunID", wr.GetRunID())

	// Synchronously wait for the workflow completion.
	var result string
	err = wr.Get(context.Background(), &result)
	if err != nil {
		log.Fatalln("Unable get workflow result", err)
	}
	log.Println("Workflow result:", result)
}
```
<!--SNIPEND-->

## Make Nexus calls across Namespaces with a development Server {#nexus-calls-across-namespaces-dev-server}

Follow the steps below to run the Nexus handler Worker, the Nexus caller Worker, and the starter.

### Run Workers connected to a local development server

Run the Nexus handler Worker:

```
cd handler
go run ./worker \
  -target-host localhost:7233 \
  -namespace my-target-namespace
```

In another terminal window, run the Nexus caller Worker:

```
cd caller
go run ./worker \
  -target-host localhost:7233 \
  -namespace my-caller-namespace
```

### Start a caller Workflow

With the Workers running, the final step in the local development process is to start a caller Workflow.

Run the starter:

```
cd caller
go run ./starter \
  -target-host localhost:7233 \
  -namespace my-caller-namespace
```

This will result in:

```
2024/10/04 19:57:40 Workflow result: Nexus Echo 👋
2024/10/04 19:57:40 Started workflow WorkflowID nexus_hello_caller_workflow_20240723195740 RunID c9789128-2fcd-4083-829d-95e43279f6d7
2024/10/04 19:57:40 Workflow result: ¡Hola! Nexus 👋
```

### Canceling a Nexus Operation {#canceling-a-nexus-operation}

To cancel a Nexus Operation from within a Workflow, create a Go context using the `workflow.WithCancel` API.
This returns a new context and a function that, when called, cancels the context and any SDK method that was passed this context.
The future returned by `NexusClient.ExecuteOperation` is resolved when the operation finishes, whether it succeeds, fails, times out, or is canceled.

Only asynchronous operations can be canceled in Nexus, as cancelation is sent using an operation token.
The Workflow or other resources backing the operation may choose to ignore the cancelation request.
If ignored, the operation may enter a terminal state.

Once the caller Workflow completes, the caller's Nexus Machinery will not make any further attempts to cancel operations that are still running.
It's okay to leave operations running in some use cases.
To ensure cancelations are delivered, wait for all pending operations to finish before exiting the Workflow.

See the [Nexus cancelation sample](https://github.com/temporalio/samples-go/tree/main/nexus-cancelation) for reference.

## Make Nexus calls across Namespaces in Temporal Cloud {#nexus-calls-across-namespaces-temporal-cloud}

This section assumes you are already familiar with [how connect a Worker to Temporal Cloud](https://docs.temporal.io/develop/go/core-application#run-a-temporal-cloud-worker).
The same [source code](https://github.com/temporalio/samples-go/tree/main/nexus) is used in this section, but the `tcld` CLI will be used to create Namespaces and the Nexus Endpoint, and mTLS client certificates will be used to securely connect the caller and handler Workers to their respective Temporal Cloud Namespaces.

### Install the latest `tcld` CLI and generate certificates

To install the latest version of the `tcld` CLI, run the following command (on MacOS):

```
brew install temporalio/brew/tcld
```

If you don't already have certificates, you can generate them for mTLS Worker authentication using the command below:

```
tcld gen ca --org $YOUR_ORG_NAME --validity-period 1y --ca-cert ca.pem --ca-key ca.key
```

These certificates will be valid for one year.

### Create caller and handler Namespaces

Before deploying to Temporal Cloud, ensure that the appropriate Namespaces are created for both the caller and handler.
If you already have these Namespaces, you don't need to do this.

```
tcld login

tcld namespace create \
  --namespace <your-caller-namespace> \
  --cloud-provider aws \
  --region us-west-2 \
  --ca-certificate-file 'path/to/your/ca.pem' \
  --retention-days 1

tcld namespace create \
  --namespace <your-target-namespace> \
  --cloud-provider aws \
  --region us-west-2 \
  --ca-certificate-file 'path/to/your/ca.pem' \
  --retention-days 1
```

Alternatively, you can create Namespaces through the UI: [https://cloud.temporal.io/Namespaces](https://cloud.temporal.io/Namespaces).

### Create a Nexus Endpoint to route requests from caller to handler

To create a Nexus Endpoint you must have a Developer account role or higher, and have NamespaceAdmin permission on the `--target-namespace`.

```
tcld nexus endpoint create \
  --name <my-nexus-endpoint-name> \
  --target-task-queue my-handler-task-queue \
  --target-namespace <my-target-namespace.account> \
  --allow-namespace <my-caller-namespace.account> \
  --description-file description.md
```

The `--allow-namespace` is used to build an Endpoint allowlist of caller Namespaces that can use the Nexus Endpoint, as described in Runtime Access Control.

Alternatively, you can create a Nexus Endpoint through the UI: [https://cloud.temporal.io/nexus](https://cloud.temporal.io/nexus).

### Run Workers Connected to Temporal Cloud with TLS certificates

Run the handler Worker:

```
cd handler

go run ./worker \
  -target-host <your-target-namespace.account>.tmprl.cloud:7233 \
  -namespace <your-target-namespace.account> \
  -client-cert 'path/to/your/ca.pem' \
  -client-key 'path/to/your/ca.key'
```

Run the caller Worker:

```
cd caller

go run ./worker \
  -target-host <your-caller-namespace.account>.tmprl.cloud:7233 \
  -namespace <your-caller-namespace.account> \
  -client-cert 'path/to/your/ca.pem' \
  -client-key 'path/to/your/ca.key'
```

### Start a caller Workflow

```
cd caller

go run ./starter \
  -target-host <your-caller-namespace.account>.tmprl.cloud:7233 \
  -namespace <your-caller-namespace.account> \
  -client-cert 'path/to/your/ca.pem' \
  -client-key 'path/to/your/ca.key'
```

This will result in:

```
2024/10/04 19:57:40 Workflow result: Nexus Echo 👋
2024/10/04 19:57:40 Workflow result: ¡Hola! Nexus 👋
```

### Run Workers Connected to Temporal Cloud with API keys

[View the source code](https://github.com/temporalio/samples-go/tree/main/nexus) in the context of the rest of the application code.

Run the handler Worker:

```
cd handler

go run ./worker \
  -target-host <region>.<cloud_provider>.api.temporal.io:7233 \
  -namespace <your-target-namespace.account> \
  -api-key <your-api-key>
```

Run the caller Worker:

```
cd caller

go run ./worker \
  -target-host <region>.<cloud_provider>.api.temporal.io:7233 \
  -namespace <your-caller-namespace.account> \
  -api-key <your-api-key>
```

### Start a caller Workflow

```
cd caller

go run ./starter \
  -target-host <region>.<cloud_provider>.api.temporal.io:7233 \
  -namespace <your-caller-namespace.account> \
  -api-key <your-api-key>
```

This will result in:

```
2024/10/04 19:57:40 Workflow result: Nexus Echo 👋
2024/10/04 19:57:40 Workflow result: ¡Hola! Nexus 👋
```

## Observability

### Web UI

A synchronous Nexus Operation will surface in the caller Workflow as follows, with just `NexusOperationScheduled` and `NexusOperationCompleted` events in the caller's Workflow history:

<CaptionedImage
    src="/img/cloud/nexus/go-sdk-observability-sync.png"
    title="Observability Sync"
/>

An asynchronous Nexus Operation will surface in the caller Workflow as follows, with `NexusOperationScheduled`, `NexusOperationStarted`, and `NexusOperationCompleted`, in the caller's Workflow history:

<CaptionedImage
    src="/img/cloud/nexus/go-sdk-observability-async.png"
    title="Observability Async"
/>

### Temporal CLI

Use the `workflow describe` command to show pending Nexus Operations in the caller Workflow and any attached callbacks on the handler Workflow:

```
temporal workflow describe -w <ID>
```

Nexus events are included in the caller's Workflow history:

```
temporal workflow show -w <ID>
```

For **asynchronous Nexus Operations** the following are reported in the caller's history:

- `NexusOperationScheduled`
- `NexusOperationStarted`
- `NexusOperationCompleted`

For **synchronous Nexus Operations** the following are reported in the caller's history:

- `NexusOperationScheduled`
- `NexusOperationCompleted`

:::note

`NexusOperationStarted` isn't reported in the caller's history for synchronous operations.

:::

## Learn more

- Read the high-level description of the [Temporal Nexus feature](/evaluate/nexus) and watch the [Nexus keynote and demo](https://youtu.be/qqc2vsv1mrU?feature=shared&t=2082).
- Learn how Nexus works in the [Nexus deep dive talk](https://www.youtube.com/watch?v=izR9dQ_eIe4) and [Encyclopedia](/nexus).
- Deploy Nexus Endpoints in production with [Temporal Cloud](/cloud/nexus).

---

## Testing - Go SDK

The Testing section of the Temporal Application development guide describes the frameworks that facilitate Workflow and integration testing.

In the context of Temporal, you can create these types of automated tests:

- **End-to-end:** Running a Temporal Server and Worker with all its Workflows and Activities; starting and interacting with Workflows from a Client.
- **Integration:** Anything between end-to-end and unit testing.
  - Running Activities with mocked Context and other SDK imports (and usually network requests).
  - Running Workers with mock Activities, and using a Client to start Workflows.
  - Running Workflows with mocked SDK imports.
- **Unit:** Running a piece of Workflow or Activity code (a function or method) and mocking any code it calls.

We generally recommend writing the majority of your tests as integration tests.

Because the test server supports skipping time, use the test server for both end-to-end and integration tests with Workers.

## Test frameworks {#test-frameworks}

The Temporal Go SDK provides a test framework to facilitate testing Workflow implementations.

This framework is suited for implementing unit tests as well as functional tests of the Workflow logic.

## Test setup

To run unit tests, we first define a test suite struct that absorbs both the basic suite functionality from [testify](https://pkg.go.dev/github.com/stretchr/testify/suite) via `suite.Suite` and the suite functionality from the Temporal test framework via `testsuite.WorkflowTestSuite`.

Because every test in this test suite will test our Workflow, we
add a property to our struct to hold an instance of the test environment. This allows us to initialize the test environment in a setup method.

For testing Workflows, we use a `testsuite.TestWorkflowEnvironment`.

```go
type UnitTestSuite struct {
        suite.Suite
        testsuite.WorkflowTestSuite

        env *testsuite.TestWorkflowEnvironment
}
```

Next, we implement a `SetupTest` method to set up a new test environment before each test.
Doing so ensures that each test runs in its own isolated sandbox.

```go
func (s *UnitTestSuite) SetupTest() {
        s.env = s.NewTestWorkflowEnvironment()
}
```

We also implement an `AfterTest` function where we assert that all the mocks we set up were indeed called by invoking `s.env.AssertExpectations(s.T())`.
Timeout for the entire test can be set using `SetTestTimeout` in the Workflow or Activity environment.

```go
func (s *UnitTestSuite) AfterTest(suiteName, testName string) {
        s.env.AssertExpectations(s.T())
}
```

Finally, we create a regular test function recognized by the `go test` command, and pass the struct to `suite.Run`.

```go
func TestUnitTestSuite(t *testing.T) {
        suite.Run(t, new(UnitTestSuite))
}
```

## Testing Activities {#test-activities}

An Activity can be tested with a mock Activity environment, which provides a way to mock the Activity context, listen to Heartbeats, and cancel the Activity.
This behavior allows you to test the Activity in isolation by calling it directly, without needing to create a Worker to run the Activity.

## Mock and override Activities

When running unit tests on Workflows, we want to test the Workflow logic in isolation. Additionally, we want to inject Activity errors during our test runs. The test framework provides two mechanisms that support these scenarios: Activity mocking and Activity overriding. Both of these mechanisms allow you to change the behavior of Activities invoked by your Workflow without the need to modify the actual Workflow code.

Let's take a look at a test that simulates a test that fails via the "Activity mocking" mechanism.

```go
func (s *UnitTestSuite) Test_SimpleWorkflow_ActivityFails() {
        s.env.OnActivity(SimpleActivity, mock.Anything, mock.Anything).Return(
          "", errors.New("SimpleActivityFailure"))
        s.env.ExecuteWorkflow(SimpleWorkflow, "test_failure")

        s.True(s.env.IsWorkflowCompleted())

        err := s.env.GetWorkflowError()
        s.Error(err)
        var applicationErr *temporal.ApplicationError
        s.True(errors.As(err, &applicationErr))
        s.Equal("SimpleActivityFailure", applicationErr.Error())
}
```

This test simulates the execution of the Activity `SimpleActivity` that is invoked by our Workflow `SimpleWorkflow` returning an error. We accomplish this by setting up a mock on the test environment for the `SimpleActivity` that returns an error.

```go
s.env.OnActivity(SimpleActivity, mock.Anything, mock.Anything).Return(
  "", errors.New("SimpleActivityFailure"))
```

With the mock set up we can now execute the Workflow via the `s.env.ExecuteWorkflow(...)` method and assert that the Workflow completed successfully and returned the expected error.

Simply mocking the execution to return a desired value or error is a pretty powerful mechanism to isolate Workflow logic.
However, sometimes we want to replace the Activity with an alternate implementation to support a more complex test scenario.
Let's assume we want to validate that the Activity gets called with the correct parameters.

```go
func (s *UnitTestSuite) Test_SimpleWorkflow_ActivityParamCorrect() {
        s.env.OnActivity(SimpleActivity, mock.Anything, mock.Anything).Return(
          func(ctx context.Context, value string) (string, error) {
                s.Equal("test_success", value)
                return value, nil
        })
        s.env.ExecuteWorkflow(SimpleWorkflow, "test_success")

        s.True(s.env.IsWorkflowCompleted())
        s.NoError(s.env.GetWorkflowError())
}
```

In this example, we provide a function implementation as the parameter to `Return`.
This allows us to provide an alternate implementation for the Activity `SimpleActivity`.
The framework will execute this function whenever the Activity is invoked and pass on the return value from the function as the result of the Activity invocation.

Additionally, the framework will validate that the signature of the "mock" function matches the signature of the original Activity function.

Since this can be an entire function, there is no limitation as to what we can do here. In this example, we assert that the `value` param has the same content as the value param we passed to the Workflow.

### Run an Activity {#run-an-activity}

If an Activity references its context, you need to mock that context when testing in isolation.

### Listen to Heartbeats {#listen-to-heartbeats}

When an Activity sends a Heartbeat, be sure that you can see the Heartbeats in your test code so that you can verify them.

### Cancel an Activity {#cancel-an-activity}

If an Activity is supposed to react to a Cancellation, you can test whether it reacts correctly by canceling it.

## Mock and override Nexus operations

Mocking Nexus operations lets you test a Workflow that executes Nexus operations without needing a
Nexus handler to run the actual Nexus operation. You can mock the Nexus operation or override its
implementation with the test Workflow environment.

Consider a test that simulates a Nexus operation call. In this example, the Nexus operation is
called `sample-operation`, the input type is `SampleInput`, the output type is `SampleOutput`, and
it belongs to the Nexus service `sample-service`.

The example bellow mocks a call to a Nexus synchronous operation, indicated by the returned value
type `*nexus.HandlerStartOperationResultSync[T]`. Since `OnNexusOperation` needs to know the
operation's name, input type and output type, and you might not have access to the Nexus operation
on the handler side, you can use `nexus.NewOperationReference` to create a Nexus operation reference
that represents the operation without its implementation (basically, it represents the signature of
the Nexus operation). You may also use the operation itself instead of creating the operation
reference if you have it available.

```go
func (s *UnitTestSuite) Test_SimpleWorkflow_NexusSyncOperation() {
        s.env.OnNexusOperation(
                "sample-service",
                nexus.NewOperationReference[SampleInput, SampleOutput]("sample-operation"),
                SampleInput{},
                workflow.NexusOperationOptions{},
        ).Return(
                &nexus.HandlerStartOperationResultSync[SampleOutput]{
                        Value: SampleOutput{},
                },
                nil, // error if you want to simulate an error in the ExecuteOperation call
        )
        // You can also add a delay to return the mock values by calling After().
        // Eg: s.env.OnNexusOperation(...).Return(...).After(1*time.Second)

        s.env.ExecuteWorkflow(SimpleWorkflow, "test_nexus_operation")

        s.True(s.env.IsWorkflowCompleted())
        s.NoError(s.env.GetWorkflowError())
}
```

Besides the synchronous operations, you can also mock asynchronous operations. The following example
demonstrates how to test a Workflow executing a Nexus asynchronous operation. The returned value
type in this case must be `*nexus.HandlerStartOperationResultAsync` with an `OperationToken`, which can
be any string of your choice. Furthermore, you must call `RegisterNexusAsyncOperationCompletion` to
register the result of the asynchronous operation identified by the tuple service name, operation
name, and operation token.

```go
func (s *UnitTestSuite) Test_SimpleWorkflow_NexusAsyncOperation() {
        s.env.OnNexusOperation(
                "sample-service",
                nexus.NewOperationReference[SampleInput, SampleOutput]("sample-operation"),
                SampleInput{},
                workflow.NexusOperationOptions{},
        ).Return(
                &nexus.HandlerStartOperationResultAsync{
                        OperationToken: "sample-operation-token",
                },
                nil, // error if you want to simulate an error in the ExecuteOperation call
        )
        err := env.RegisterNexusAsyncOperationCompletion(
                "sample-service",
                "sample-operation",
                "sample-operation-token", // must match the OperationToken above
                SampleOutput{},
                nil,            // error if you want to simulate an error in the operation
                2*time.Second,  // delay to simulate how long the operation takes after it starts
        )
        s.NoError(err)
        s.env.ExecuteWorkflow(SimpleWorkflow, "test_nexus_operation")

        s.True(s.env.IsWorkflowCompleted())
        s.NoError(s.env.GetWorkflowError())
}
```

If your Workflow executes multiple Nexus asynchronous operations, you can mock each of them with
different operation tokens, and register the completion results using the corresponding operation token.

If mocking Nexus operations is not enough, and you need to run some custom logic when the Nexus
operation is executed, you can override it as follows.

```go
func (s *UnitTestSuite) Test_SimpleWorkflow_NexusSyncOperation() {
        var SampleOperation = nexus.NewSyncOperation(
                "sample-operation",
                func(ctx context.Context, input SampleInput, options nexus.StartOperationOptions) (SampleOutput, error) {
                        // Custom logic here.
                        return SampleOutput{}, nil
                },
        )

        service := nexus.NewService("sample-service")
        s.NoError(service.Register(SampleOperation))
        env.RegisterNexusService(service)
        s.env.ExecuteWorkflow(SimpleWorkflow, "test_nexus_operation")

        s.True(s.env.IsWorkflowCompleted())
        s.NoError(s.env.GetWorkflowError())
}
```

The following example shows how to override a Nexus asynchronous operation.

```go
func (s *UnitTestSuite) Test_SimpleWorkflow_NexusSyncOperation() {
        SampleHandlerWorkflow := func(_ workflow.Context, input SampleInput) (SampleOutput, error) {
                // Custom logic here.
                return SampleOutput{}, nil
        }
        SampleOperation := nexus.NewWorkflowRunOperation(
                "sample-operation",
                SampleHandlerWorkflow,
                func(ctx context.Context, input SampleInput, options nexus.StartOperationOptions) (client.StartWorkflowOptions, error) {
                        // Custom logic to build client.StartWorkflowOptions.
                        return client.StartWorkflowOptions{}, nil
                },
        )

        service := nexus.NewService("sample-service")
        s.NoError(service.Register(SampleOperation))
        env.RegisterNexusService(service)
        s.env.ExecuteWorkflow(SimpleWorkflow, "test_nexus_operation")

        s.True(s.env.IsWorkflowCompleted())
        s.NoError(s.env.GetWorkflowError())
}
```

## Testing Workflows {#test-workflows}

When running unit tests on Workflows, we want to test the Workflow logic in isolation.
The simplest test case we can write is to have the test environment execute the Workflow and then evaluate the results.

```go
func (s *UnitTestSuite) Test_SimpleWorkflow_Success() {
        s.env.ExecuteWorkflow(SimpleWorkflow, "test_success")

        s.True(s.env.IsWorkflowCompleted())
        s.NoError(s.env.GetWorkflowError())
}
```

Calling `s.env.ExecuteWorkflow(...)` executes the Workflow logic and any invoked Activities inside the test process. The first parameter of `s.env.ExecuteWorkflow(...)` contains the Workflow functions, and any subsequent parameters contain values for custom input parameters declared by the Workflow.

> Note that unless the Activity invocations are mocked or Activity implementation replaced (see [Activity mocking and overriding](#mock-and-override-activities)), the test environment will execute the actual Activity code including any calls to outside services.

After executing the Workflow in the above example, we assert that the Workflow ran through completion via the call to `s.env.IsWorkflowCompleted()`. We also assert that no errors were returned by asserting on the return value of `s.env.GetWorkflowError()`.
If our Workflow returned a value, we could have retrieved that value via a call to `s.env.GetWorkflowResult(&value)` and had additional asserts on that value.

### Query tests

`TestWorkflowEnvironment` instances have a [`QueryWorkflow()` method](https://pkg.go.dev/go.temporal.io/temporal/internal#TestWorkflowEnvironment.QueryWorkflow) that lets you query the state of the currently running Workflow.
For example, suppose you have a Workflow that lets you query the progress of a long running task as shown below.

```go
func ProgressWorkflow(ctx workflow.Context, percent int) error {
	logger := workflow.GetLogger(ctx)

	err := workflow.SetQueryHandler(ctx, "getProgress", func(input []byte) (int, error) {
		return percent, nil
	})
	if err != nil {
		logger.Info("SetQueryHandler failed.", "Error", err)
		return err
	}

	for percent = 0; percent<100; percent++ {
                // Important! Use `workflow.Sleep()`, not `time.Sleep()`, because Temporal's
                // test environment doesn't stub out `time.Sleep()`.
		workflow.Sleep(ctx, time.Second*1)
	}

	return nil
}
```

This Workflow tracks the current progress of a task in percentage terms, and increments the percentage by 1 every second.
Below is how you would write a test case that queries this Workflow.
Note that you should always query the Workflow either after `ExecuteWorkflow()` is done or in a `RegisterDelayedCallback()` callback, otherwise you'll get a `runtime error` panic.

```go
func (s *UnitTestSuite) Test_ProgressWorkflow() {
	value := 0

	// After 10 seconds plus padding, progress should be 10.
	// Note that `RegisterDelayedCallback()` doesn't actually make your test wait for 10 seconds!
	// Temporal's test framework advances time internally, so this test should take < 1 second.
	s.env.RegisterDelayedCallback(func() {
		res, err := s.env.QueryWorkflow("getProgress")
		s.NoError(err)
		err = res.Get(&value)
		s.NoError(err)
		s.Equal(10, value)
	}, time.Second*10+time.Millisecond*1)

	s.env.ExecuteWorkflow(ProgressWorkflow, 0)

	s.True(s.env.IsWorkflowCompleted())

	// Once the workflow is completed, progress should always be 100
	res, err := s.env.QueryWorkflow("getProgress")
	s.NoError(err)
	err = res.Get(&value)
	s.NoError(err)
	s.Equal(value, 100)
}
```

:::note

`RegisterDelayedCallback` can also be used to send [Signals](/sending-messages#sending-signals).
When using "Signal-With-Start", set the delay to `0`.
:::

### How to mock Activities {#mock-activities}

Mock the Activity invocation when unit testing your Workflows.

When integration testing Workflows with a Worker, you can mock Activities by providing mock Activity implementations to the Worker.

### How to skip time {#skip-time}

Some long-running Workflows can persist for months or even years.
Implementing the test framework allows your Workflow code to skip time and complete your tests in seconds rather than the Workflow's specified amount.

For example, if you have a Workflow sleep for a day, or have an Activity failure with a long retry interval, you don't need to wait the entire length of the sleep period to test whether the sleep function works.
Instead, test the logic that happens after the sleep by skipping forward in time and complete your tests in a timely manner.

The test framework included in most SDKs is an in-memory implementation of Temporal Server that supports skipping time.
Time is a global property of an instance of `TestWorkflowEnvironment`: skipping time (either automatically or manually) applies to all currently running tests.
If you need different time behaviors for different tests, run your tests in a series or with separate instances of the test server.
For example, you could run all tests with automatic time skipping in parallel, and then all tests with manual time skipping in series, and then all tests without time skipping in parallel.

#### Set up time skipping {#setting-up}

Set up the time-skipping test framework in the SDK of your choice.

{/* #### Skip time automatically {#automatic-method} */}

You can skip time automatically in the SDK of your choice.
Start a test server process that skips time as needed.
For example, in the time-skipping mode, Timers, which include sleeps and conditional timeouts, are fast-forwarded except when Activities are running.

{/* #### Skip time manually {#manual-method} */}

Skip time manually in the SDK of your choice.

#### Skip time in Activities {#skip-time-in-activities}

Skip time in Activities in the SDK of your choice.

## How to Replay a Workflow Execution {#replay}

Replay recreates the exact state of a Workflow Execution.
You can replay a Workflow from the beginning of its Event History.

Replay succeeds only if the [Workflow Definition](/workflow-definition) is compatible with the provided history from a deterministic point of view.

When you test changes to your Workflow Definitions, we recommend doing the following as part of your CI checks:

1. Determine which Workflow Types or Task Queues (or both) will be targeted by the Worker code under test.
2. Download the Event Histories of a representative set of recent open and closed Workflows from each Task Queue, either programmatically using the SDK client or via the Temporal CLI.
3. Run the Event Histories through replay.
4. Fail CI if any error is encountered during replay.

The following are examples of fetching and replaying Event Histories:

Use the [worker.WorkflowReplayer](https://pkg.go.dev/go.temporal.io/sdk/worker#WorkflowReplayer) to replay an existing Workflow Execution from its Event History to replicate errors.

For example, the following code retrieves the Event History of a Workflow:

```go

	"context"

	"go.temporal.io/api/enums/v1"
	"go.temporal.io/api/history/v1"
	"go.temporal.io/sdk/client"
)

func GetWorkflowHistory(ctx context.Context, client client.Client, id, runID string) (*history.History, error) {
	var hist history.History
	iter := client.GetWorkflowHistory(ctx, id, runID, false, enums.HISTORY_EVENT_FILTER_TYPE_ALL_EVENT)
	for iter.HasNext() {
		event, err := iter.Next()
		if err != nil {
			return nil, err
		}
		hist.Events = append(hist.Events, event)
	}
	return &hist, nil
}
```

This history can then be used to _replay_.
For example, the following code creates a `WorkflowReplayer` and register the `YourWorkflow` Workflow function.
Then it calls the `ReplayWorkflowHistory` to _replay_ the Event History and return an error code.

```go

	"context"

	"go.temporal.io/sdk/client"
	"go.temporal.io/sdk/worker"
)

func ReplayWorkflow(ctx context.Context, client client.Client, id, runID string) error {
	hist, err := GetWorkflowHistory(ctx, client, id, runID)
	if err != nil {
		return err
	}
	replayer := worker.NewWorkflowReplayer()
	replayer.RegisterWorkflow(YourWorkflow)
	return replayer.ReplayWorkflowHistory(nil, hist)
}
```

The code above will cause the Worker to re-execute the Workflow's Workflow Function using the original Event History.
If a noticeably different code path was followed or some code caused a deadlock, it will be returned in the error code.
Replaying a Workflow Execution locally is a good way to see exactly what code path was taken for given input and events.

You can replay many Event Histories by registering all the needed Workflow implementation and then calling `ReplayWorkflowHistory` repeatedly.

---

## Durable Timers - Go SDK

A Workflow can set a Durable Timer for a fixed time period.
In some SDKs, the function is called `sleep()`, and in others, it's called `timer()`.

A Workflow can sleep for days, months, or even years.
Timers are persisted, so even if your Worker or Temporal Service is down when the time period completes, as soon as your Worker and Temporal Service are back up, the `sleep()` call will resolve and your code will continue executing.

Sleeping is a resource-light operation: it does not tie up the process, and you can run millions of Timers off a single Worker.

To set a Timer in Go, use the [`NewTimer()`](https://pkg.go.dev/go.temporal.io/sdk/workflow#NewTimer) function and pass the duration you want to wait before continuing.

```go
timer := workflow.NewTimer(timerCtx, duration)
```

To set a sleep duration in Go, use the [`sleep()`](https://pkg.go.dev/go.temporal.io/sdk/workflow#Sleep) function and pass the duration you want to wait before continuing.
A zero or negative sleep duration causes the function to return immediately.

```go
sleep = workflow.Sleep(ctx, 10*time.Second)
```

For more information, see the [Timer](https://github.com/temporalio/samples-go/tree/main/timer) example in the [Go Samples repository](https://github.com/temporalio/samples-go).

---

## Versioning - Go SDK

Since Workflow Executions in Temporal can run for long periods — sometimes months or even years — it's common to need to make changes to a Workflow Definition, even while a particular Workflow Execution is in progress.

The Temporal Platform requires that Workflow code is [deterministic](/workflow-definition#deterministic-constraints).
If you make a change to your Workflow code that would cause non-deterministic behavior on Replay, you'll need to use one of our Versioning methods to gracefully update your running Workflows.
With Versioning, you can modify your Workflow Definition so that new executions use the updated code, while existing ones continue running the original version.
There are two primary Versioning methods that you can use:

- [Worker Versioning](/production-deployment/worker-deployments/worker-versioning). The Worker Versioning feature allows you to tag your Workers and programmatically roll them out in versioned deployments, so that old Workers can run old code paths and new Workers can run new code paths.
- [Versioning with Patching](#patching). This method works by adding branches to your code tied to specific revisions. It applies a code change to new Workflow Executions while avoiding disruptive changes to in-progress Workflow Executions.

:::danger
Support for the experimental Worker Versioning method before 2025 will be removed from Temporal Server in March 2026. Refer to the [latest Worker Versioning docs](/worker-versioning) for guidance. You can still refer to the [Worker Versioning Legacy](worker-versioning-legacy) docs if needed. 
:::

## Worker Versioning

Temporal's [Worker Versioning](/production-deployment/worker-deployments/worker-versioning) feature allows you to tag your Workers and programmatically roll them out in Deployment Versions, so that old Workers can run old code paths and new Workers can run new code paths. This way, you can pin your Workflows to specific revisions, avoiding the need for patching.

## Versioning with Patching {#patching}

### Patching with GetVersion

A Patch defines a logical branch in a Workflow for a specific change, similar to a feature flag.
It applies a code change to new Workflow Executions while avoiding disruptive changes to in-progress Workflow Executions.
When you want to make substantive code changes that may affect existing Workflow Executions, create a patch. Note that there's no need to patch [Pinned Workflows](/worker-versioning).

Consider the following Workflow Definition:

```go
func YourWorkflow(ctx workflow.Context, data string) (string, error) {
        ao := workflow.ActivityOptions{
                ScheduleToStartTimeout: time.Minute,
                StartToCloseTimeout:    time.Minute,
        }
        ctx = workflow.WithActivityOptions(ctx, ao)
        var result1 string
        err := workflow.ExecuteActivity(ctx, ActivityA, data).Get(ctx, &result1)
        if err != nil {
                return "", err
        }
        var result2 string
        err = workflow.ExecuteActivity(ctx, ActivityB, result1).Get(ctx, &result2)
        return result2, err
}
```

Suppose you replaced `ActivityA` with `ActivityC` and deployed the updated code.

If an existing Workflow Execution was started by the original version of the Workflow code, where `ActivityA` was run, and then resumed running on a new Worker where it was replaced with `ActivityC`, the server side Event History would be out of sync.
This would cause the Workflow to fail with a nondeterminism error.

To resolve this, you can use `workflow.GetVersion()` to patch to your Workflow:

```go
var err error
v := workflow.GetVersion(ctx, "Step1", workflow.DefaultVersion, 1)
if v == workflow.DefaultVersion {
        err = workflow.ExecuteActivity(ctx, ActivityA, data).Get(ctx, &result1)
} else {
        err = workflow.ExecuteActivity(ctx, ActivityC, data).Get(ctx, &result1)
}
if err != nil {
        return "", err
}

var result2 string
err = workflow.ExecuteActivity(ctx, ActivityB, result1).Get(ctx, &result2)
return result2, err
```

When `workflow.GetVersion()` is run for the new Workflow Execution, it records a marker in the Event History so that all future calls to `GetVersion` for this change Id — `Step 1` in the example — on this Workflow Execution will always return the given version number, which is `1` in the example.

If you make an additional change, such as replacing ActivityC with ActivityD, you need to
add some additional code:

```go
v := workflow.GetVersion(ctx, "Step1", workflow.DefaultVersion, 2)
if v == workflow.DefaultVersion {
        err = workflow.ExecuteActivity(ctx, ActivityA, data).Get(ctx, &result1)
} else if v == 1 {
        err = workflow.ExecuteActivity(ctx, ActivityC, data).Get(ctx, &result1)
} else {
        err = workflow.ExecuteActivity(ctx, ActivityD, data).Get(ctx, &result1)
}
```

Note that we changed `maxSupported` from 1 to 2.
A Workflow that has already passed this `GetVersion()` call before it was introduced returns `DefaultVersion`.
A Workflow that was run with `maxSupported` set to 1 returns 1.
New Workflows return 2.

After all the Workflow Executions prior to version 1 have left retention, you can remove the code for that version:

```go
v := workflow.GetVersion(ctx, "Step1", 1, 2)
if v == 1 {
        err = workflow.ExecuteActivity(ctx, ActivityC, data).Get(ctx, &result1)
} else {
        err = workflow.ExecuteActivity(ctx, ActivityD, data).Get(ctx, &result1)
}
```

You'll note that `minSupported` has changed from `DefaultVersion` to `1`.
If an older version of the Workflow Execution history is replayed on this code, it fails because the minimum expected version is 1.
After all the Workflow Executions for version 1 have left retention, you can remove version 1 so that your code looks like the following:

```go
_ := workflow.GetVersion(ctx, "Step1", 2, 2)
err = workflow.ExecuteActivity(ctx, ActivityD, data).Get(ctx, &result1)
```

Note that we have preserved the call to `GetVersion()`. There are two reasons to preserve this call:

1. This ensures that if there is a Workflow Execution still running for an older version, it will
   fail here and not proceed.
2. If you need to make additional changes for `Step1`, such as changing ActivityD to ActivityE, you
   only need to update `maxVersion` from 2 to 3 and branch from there.

You need to preserve only the first call to `GetVersion()` for each `changeID`.
All subsequent calls to `GetVersion()` with the same change Id are safe to remove.
If necessary, you can remove the first `GetVersion()` call, but you need to ensure the following:

- All executions with an older version have left retention.
- You can no longer use `Step1` for the changeId. If you need to make changes to that same part in
  the future, such as change from ActivityD to ActivityE, you would need to use a different changeId
  like `Step1-fix2`, and start minVersion from DefaultVersion again. The code would look like the
  following:

```go
v := workflow.GetVersion(ctx, "Step1-fix2", workflow.DefaultVersion, 1)
if v == workflow.DefaultVersion {
        err = workflow.ExecuteActivity(ctx, ActivityD, data).Get(ctx, &result1)
} else {
        err = workflow.ExecuteActivity(ctx, ActivityE, data).Get(ctx, &result1)
}
```

You can add multiple calls to `GetVersion` in a single Workflow.
This can become challenging to manage if you have many long-running Workflows, as you will wind up with many code branches over time.
To clean these up, you can gradually deprecate older Workflow versions.

### Deprecating old Workflow versions

You can safely remove support for older Workflow versions once you are certain that there are no longer any open Workflow Executions based on that version. You can use the following [List Filter](/list-filter) syntax for this (the 1 near the end of the last line represents the version number):

```
WorkflowType = "PizzaWorkflow" 
    AND ExecutionStatus = "Running" 
    AND TemporalChangeVersion="ChangedNotificationActivityType-1"
```

Since Workflow Executions that were started before `GetVersion` was added to the code won't have the associated Marker in their Event History, you'll need to use a different query to determine if any of those are still running:

```
WorkflowType = "PizzaWorkflow" 
    AND ExecutionStatus = "Running" 
    AND TemporalChangeVersion IS NULL
```

If you have found that there are no longer any open executions for the first two versions of the Workflow, for example, then you could remove support for them by changing the code as shown below:

```go
version := GetVersion(ctx, "ChangedNotificationActivityType", 2, 3)
if version  == 2 {
    err = workflow.ExecuteActivity(ctx, SendTextMessage).Get(ctx, nil)
} else {
    err = workflow.ExecuteActivity(ctx, SendTweet).Get(ctx, nil)
}
```

Patching allows you to make changes to currently running Workflows.
It is a powerful method for introducing compatible changes without introducing non-determinism errors.

### Workflow cutovers

To understand why Patching is useful, it's helpful to demonstrate cutting over an entire Workflow.

Since incompatible changes only affect open Workflow Executions of the same type, you can avoid determinism errors by creating a whole new Workflow when making changes.
To do this, you can copy the Workflow Definition function, giving it a different name, and register both names with your Workers.

For example, you would duplicate `PizzaWorkflow` as `PizzaWorkflowV2`:

```go
func PizzaWorkflow(ctx workflow.Context, order PizzaOrder) (OrderConfirmation, error) {
    // this function contains the original code
}

func PizzaWorkflowV2(ctx workflow.Context, order PizzaOrder) (OrderConfirmation, error) {
    // this function contains the updated code
}
```

You can use any name you like for the new function, so long as the first character remains uppercase (this is a requirement for any Workflow Definition, since it must use an exported function).
Using some type of version identifier, such as V2 in this example, will make it easier to identify the change.

You would then need to update the Worker configuration, and any other identifier strings, to register both Workflow Types:

```go
w.RegisterWorkflow(pizza.PizzaWorkflow)
w.RegisterWorkflow(pizza.PizzaWorkflowV2)
```

The downside of this method is that it requires you to duplicate code and to update any commands used to start the Workflow.
This can become impractical over time.
This method also does not provide a way to version any still-running Workflows -- it is essentially just a cutover, unlike Patching.

## Runtime checking {#runtime-checking}

The Temporal Go SDK performs a runtime check to help prevent obvious incompatible changes.
Adding, removing, or reordering any of these methods without Versioning triggers the runtime check and results in a nondeterminism error:

- `workflow.ExecuteActivity()`
- `workflow.ExecuteChildWorkflow()`
- `workflow.NewTimer()`
- `workflow.RequestCancelWorkflow()`
- `workflow.SideEffect()`
- `workflow.SignalExternalWorkflow()`
- `workflow.Sleep()`

The runtime check does not perform a thorough check.
For example, it does not check on the Activity's input arguments or the Timer duration.
Each Temporal SDK implements these sanity checks differently, and they are not a complete check for non-deterministic changes.
Instead, you should incorporate [Replay Testing](/develop/go/testing-suite#replay) when making revisions.

---

## Worker Versioning (Legacy) - Go SDK

## How to use Worker Versioning in Go (Deprecated) {#worker-versioning}

:::caution

This section is for a deprecated Worker Versioning API. Please redirect your attention to [Worker Versioning](/production-deployment/worker-deployments/worker-versioning).

See the [Pre-release README](https://github.com/temporalio/temporal/blob/main/docs/worker-versioning.md) for more information.

:::

A Build ID corresponds to a deployment. If you don't already have one, we recommend a hash of the code--such as a Git SHA--combined with a human-readable timestamp.
To use Worker Versioning, you need to pass a Build ID to your Go Worker and opt in to Worker Versioning.

### Assign a Build ID to your Worker and opt in to Worker Versioning

You should understand assignment rules before completing this step.
See the [Worker Versioning Pre-release README](https://github.com/temporalio/temporal/blob/main/docs/worker-versioning.md) for more information.

To enable Worker Versioning for your Worker, assign the Build ID--perhaps from an environment variable--and turn it on.

```go
// ...
workerOptions := worker.Options{
   BuildID: buildID,
   UseBuildIDForVersioning: true,
// ...
}
w := worker.New(c, "your_task_queue_name", workerOptions)
// ...
```

:::warning

Importantly, when you start this Worker, it won't receive any tasks until you set up assignment rules.

:::

### Specify versions for Activities, Child Workflows, and Continue-as-New Workflows

By default, Activities, Child Workflows, and Continue-as-New Workflows are run on the build of the Workflow that created them if they are also configured to run on the same Task Queue.
When configured to run on a separate Task Queue, they will default to using the current assignment rules.

If you want to override this behavior, you can specify your intent via the `VersioningIntent` field on the appropriate options struct.

For example, if you want an Activity to use the latest assignment rules rather than inheriting from its parent:

```go
// ...
ao := workflow.ActivityOptions{
    VersioningIntent: VersioningIntentUseAssignmentRules,
    // ...other options
}
activityCtx := workflow.WithActivityOptions(ctx, ao)
var yourActivityResult YourActivityResultType
err := workflow.ExecuteActivity(ctx, YourActivityDefinition, yourActivityParam).Get(ctx, &yourActivityResult)
// ...
```

#### Specifying versions for Continue-As-New

When using the Continue-As-New feature, use the `WithWorkflowVersioningIntent` context modifier:

```go
ctx = workflow.WithWorkflowVersioningIntent(ctx, temporal.VersioningIntentUseAssignmentRules)
err := workflow.NewContinueAsNewError(ctx, "WorkflowName")
```

### Tell the Task Queue about your Worker's Build ID (Deprecated)

:::caution

This section is for a deprecated Worker Versioning API. Please redirect your attention to [Worker Versioning](/production-deployment/worker-deployments/worker-versioning).

:::

Now you can use the SDK (or the Temporal CLI) to tell the Task Queue about your Worker's Build ID.
You might want to do this as part of your CI deployment process.

```go
// ...
err := client.UpdateWorkerBuildIdCompatibility(ctx, &client.UpdateWorkerBuildIdCompatibilityOptions{
   TaskQueue: "your_task_queue_name",
   Operation: &client.BuildIDOpAddNewIDInNewDefaultSet{
      BuildID: "deadbeef",
   },
})
```

This code adds the `deadbeef` Build ID to the Task Queue as the sole version in a new version set, which becomes the default for the queue.
New Workflows execute on Workers with this Build ID, and existing ones will continue to process by appropriately compatible Workers.

If, instead, you want to add the Build ID to an existing compatible set, you can do this:

```go
// ...
err := client.UpdateWorkerBuildIdCompatibility(ctx, &client.UpdateWorkerBuildIdCompatibilityOptions{
   TaskQueue: "your_task_queue_name",
   Operation: &client.BuildIDOpAddNewCompatibleVersion{
      BuildID:                   "deadbeef",
      ExistingCompatibleBuildId: "some-existing-build-id",
   },
})
```

This code adds `deadbeef` to the existing compatible set containing `some-existing-build-id` and marks it as the new default Build ID for that set.

You can also promote an existing Build ID in a set to be the default for that set:

```go
// ...
err := client.UpdateWorkerBuildIdCompatibility(ctx, &client.UpdateWorkerBuildIdCompatibilityOptions{
   TaskQueue: "your_task_queue_name",
   Operation: &client.BuildIDPromoteIDWithinSet{
      BuildID: "some-existing-build-id",
   },
})
```

---

## Develop durable applications with Temporal SDKs

The Temporal SDK developer guides provide a comprehensive overview of the structures, primitives, and features used in [Temporal Application](/temporal#temporal-application) development.

<SdkLogos />

- Go SDK [developer guide](/develop/go) and [API reference](http://t.mp/go-api)
- Java SDK [developer guide](/develop/java) and [API reference](http://t.mp/java-api)
- PHP SDK [developer guide](/develop/php) and [API reference](https://php.temporal.io/namespaces/temporal.html)
- Python SDK [developer guide](/develop/python) and [API reference](https://python.temporal.io)
- TypeScript SDK [developer guide](/develop/typescript) and [API reference](https://typescript.temporal.io)
- .NET SDK [developer guide](/develop/dotnet) and [API reference](https://dotnet.temporal.io/)
- Ruby SDK [developer guide](/develop/ruby) and [API reference](https://ruby.temporal.io/)

---

## Asynchronous Activity Completion - Java SDK

This page shows how to asynchronously complete an Activity

[Asynchronous Activity Completion](/activity-execution#asynchronous-activity-completion) enables the Activity Function to return without the Activity Execution completing.

There are three steps to follow:

1. The Activity provides the external system with identifying information needed to complete the Activity Execution.
   Identifying information can be a [Task Token](/activity-execution#task-token), or a combination of Namespace, Workflow Id, and Activity Id.
2. The Activity Function completes in a way that identifies it as waiting to be completed by an external system.
3. The Temporal Client is used to Heartbeat and complete the Activity.

To complete an Activity asynchronously, set the [`ActivityCompletionClient`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/ActivityCompletionClient.html) interface to the `complete()` method.

```java
    @Override
    public String composeGreeting(String greeting, String name) {

      // Get the activity execution context
      ActivityExecutionContext context = Activity.getExecutionContext();

      // Set a correlation token that can be used to complete the activity asynchronously
      byte[] taskToken = context.getTaskToken();

      /**
       * For the example we will use a {@link java.util.concurrent.ForkJoinPool} to execute our
       * activity. In real-life applications this could be any service. The composeGreetingAsync
       * method is the one that will actually complete workflow action execution.
       */
      ForkJoinPool.commonPool().execute(() -> composeGreetingAsync(taskToken, greeting, name));
      context.doNotCompleteOnReturn();

      // Since we have set doNotCompleteOnReturn(), the workflow action method return value is
      // ignored.
      return "ignored";
    }

    // Method that will complete action execution using the defined ActivityCompletionClient
    private void composeGreetingAsync(byte[] taskToken, String greeting, String name) {
      String result = greeting + " " + name + "!";

      // Complete our workflow activity using ActivityCompletionClient
      completionClient.complete(taskToken, result);
    }
  }
```

Alternatively, set the [`doNotCompleteOnReturn()`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/activity/ActivityExecutionContext.html#doNotCompleteOnReturn()) method during an Activity Execution.

```java
    @Override
    public String composeGreeting(String greeting, String name) {

      // Get the activity execution context
      ActivityExecutionContext context = Activity.getExecutionContext();

      // Set a correlation token that can be used to complete the activity asynchronously
      byte[] taskToken = context.getTaskToken();

      /**
       * For the example we will use a {@link java.util.concurrent.ForkJoinPool} to execute our
       * activity. In real-life applications this could be any service. The composeGreetingAsync
       * method is the one that will actually complete workflow action execution.
       */
      ForkJoinPool.commonPool().execute(() -> composeGreetingAsync(taskToken, greeting, name));
      context.doNotCompleteOnReturn();

      // Since we have set doNotCompleteOnReturn(), the workflow action method return value is
      // ignored.
      return "ignored";
    }
```

When this method is called during an Activity Execution, the Activity Execution does not complete when its method returns.

---

## Benign exceptions - Java SDK

**How to mark an Activity error as benign using the Temporal Java SDK**

When Activities throw errors that are expected or not severe, they can create noise in your logs, metrics, and OpenTelemetry traces, making it harder to identify real issues.
By marking these errors as benign, you can exclude them from your observability data while still handling them in your Workflow logic.

To mark an error as benign, set the category to `ApplicationErrorCategory.BENIGN` using the [`ApplicationFailure`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/failure/ApplicationFailure.html) builder.

Benign errors:
- Have Activity failure logs downgraded to DEBUG level
- Do not emit Activity failure metrics
- Do not set the OpenTelemetry failure status to ERROR

```java

@ActivityInterface
public interface MyActivities {
  @ActivityMethod
  String myActivity();
}

public class MyActivitiesImpl implements MyActivities {
  @Override
  public String myActivity() {
    try {
      return callExternalService();
    } catch (Exception e) {
      // Mark this error as benign since it's expected
      throw ApplicationFailure.newBuilder()
          .setMessage(e.getMessage())
          .setType(e.getClass().getName())
          .setCause(e)
          .setCategory(ApplicationErrorCategory.BENIGN)
          .build();
    }
  }
}
```

Use benign exceptions for Activity errors that occur regularly as part of normal operations, such as polling an external service that isn't ready yet, or handling expected transient failures that will be retried.

---

## Interrupt a Workflow Execution - Java SDK

You can interrupt a Workflow Execution in one of the following ways:

- [Cancel](#cancellation): Canceling a Workflow provides a graceful way to stop Workflow Execution.
- [Terminate](#termination): Terminating a Workflow forcefully stops Workflow Execution.

Terminating a Workflow forcefully stops Workflow Execution. This action resembles killing a process.

- The system records a `WorkflowExecutionTerminated` event in the Workflow History.
- The termination forcefully and immediately stops the Workflow Execution.
- The Workflow code gets no chance to handle termination.
- A Workflow Task doesn't get scheduled.

In most cases, canceling is preferable because it allows the Workflow to finish gracefully. Terminate only if the
Workflow is stuck and cannot be canceled normally.

## Cancel a Workflow Execution {#cancellation}

Canceling a Workflow provides a graceful way to stop Workflow Execution. This action resembles sending a `SIGTERM` to a
process.

- The system records a `WorkflowExecutionCancelRequested` event in the Workflow History.
- A Workflow Task gets scheduled to process the cancelation.
- The Workflow code can handle the cancelation and execute any cleanup logic.
- The system doesn't forcefully stop the Workflow.

To cancel a Workflow Execution in Java, use the
[cancel()](<https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#cancel()>)
function on the WorkflowStub.

```java
WorkflowStub workflowStub = WorkflowStub.fromTyped(workflow);
workflowStub.cancel();
```

## Cancellation scopes in Java {#cancellation-scopes}

In the Java SDK, Workflows are represented internally by a tree of cancellation scopes, each with cancellation behaviors
you can specify. By default, everything runs in the "root" scope.

Scopes are created using the
[Workflow.newCancellationScope](<https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#newCancellationScope(io.temporal.workflow.Functions.Proc1)>)
constructor

Cancellations are applied to cancellation scopes, which can encompass an entire Workflow or just part of one. Scopes can
be nested, and cancellation propagates from outer scopes to inner ones. A Workflow's method runs in the outermost scope.
Cancellations are handled by catching `CanceledFailure`s thrown by cancelable operations.

You can also use the following APIs:

- `CancellationScope.current()`: Get the current scope.
- `scope.cancel()`: Cancel all operations inside a `scope`.
- `scope.getCancellationRequest()`: A promise that resolves when a scope cancellation is requested, such as when
  Workflow code calls `cancel()` or the entire Workflow is cancelled by an external client.

When a `CancellationScope` is cancelled, it propagates cancellation in any child scopes and of any cancelable operations
created within it, such as the following:

- Activities
- Timers (created with the
  [sleep](<https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#sleep(java.time.Duration)>)
  function)
- Child Workflows
- Nexus Operations

### Cancel an Activity from a Workflow {#cancel-activity}

Canceling an Activity from within a Workflow requires that the Activity Execution sends Heartbeats and sets a Heartbeat
Timeout. If the Heartbeat is not invoked, the Activity cannot receive a cancellation request. When any non-immediate
Activity is executed, the Activity Execution should send Heartbeats and set a
[Heartbeat Timeout](/encyclopedia/detecting-activity-failures#heartbeat-timeout) to ensure that the server knows it is
still working.

When an Activity is canceled, an error is raised in the Activity at the next available opportunity. If cleanup logic
needs to be performed, it can be done in a `finally` clause or inside a caught cancel error. However, for the Activity
to appear canceled the exception needs to be re-raised.

:::note

Unlike regular Activities, [Local Activities](/local-activity) currently do not support cancellation.

:::

To cancel an Activity from a Workflow Execution, call the
[cancel()](<https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/CancellationScope.html#cancel()>)
method on the CancellationScope that the activity was started in.

```java
public class GreetingWorkflowImpl implements GreetingWorkflow {
    @Override
    public String getGreeting(String name) {
      List<Promise<String>> results = new ArrayList<>(greetings.length);

      /*
       * Create our CancellationScope. Within this scope we call the workflow activity
       * composeGreeting method asynchronously for each of our defined greetings in different
       * languages.
       */
      CancellationScope scope =
          Workflow.newCancellationScope(
              () -> {
                for (String greeting : greetings) {
                  results.add(Async.function(activities::composeGreeting, greeting, name));
                }
              });

      /*
       * Execute all activities within the CancellationScope. Note that this execution is
       * non-blocking as the code inside our cancellation scope is also non-blocking.
       */
      scope.run();

      // We use "anyOf" here to wait for one of the activity invocations to return
      String result = Promise.anyOf(results).get();

      // Trigger cancellation of all uncompleted activity invocations within the cancellation scope
      scope.cancel();

      /*
       *  Wait for all activities to perform cleanup if needed.
       *  For the sake of the example we ignore cancellations and
       *  get all the results so that we can print them in the end.
       *
       *  Note that we cannot use "allOf" here as that fails on any Promise failures
       */
      for (Promise<String> activityResult : results) {
        try {
          activityResult.get();
        } catch (ActivityFailure e) {
          if (!(e.getCause() instanceof CanceledFailure)) {
            throw e;
          }
        }
      }
      return result;
    }
}
```

## Terminate a Workflow Execution {#termination}

Terminating a Workflow forcefully stops Workflow Execution. This action resembles killing a process.

- The system records a `WorkflowExecutionTerminated` event in the Workflow History.
- The termination forcefully and immediately stops the Workflow Execution.
- The Workflow code gets no chance to handle termination.
- A Workflow Task doesn't get scheduled.

To terminate a Workflow Execution in Java, use the
[terminate()](<https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#terminate(java.lang.String,java.lang.Object...)>)
function on the WorkflowStub.

```java
WorkflowStub untyped = WorkflowStub.fromTyped(myWorkflowStub);
untyped.terminate("Sample reason");
```

## Reset a Workflow Execution {#reset}

Resetting a Workflow Execution terminates the current Workflow Execution and starts a new Workflow Execution from a
point you specify in its Event History. Use reset when a Workflow is blocked due to a non-deterministic error or other
issues that prevent it from completing.

When you reset a Workflow, the Event History up to the reset point is copied to the new Workflow Execution, and the
Workflow resumes from that point with the current code. Reset only works if you've fixed the underlying issue, such as
removing non-deterministic code. Any progress made after the reset point will be discarded. Provide a reason when
resetting, as it will be recorded in the Event History.

<Tabs>

<TabItem value="web-ui" label="Web UI">

1. Navigate to the Workflow Execution details page,
2. Click the **Reset** button in the top right dropdown menu,
3. Select the Event ID to reset to,
4. Provide a reason for the reset,
5. Confirm the reset.

The Web UI shows available reset points and creates a link to the new Workflow Execution after the reset completes.

</TabItem>

<TabItem value="cli" label="Temporal CLI">

Use the `temporal workflow reset` command to reset a Workflow Execution:

```bash
temporal workflow reset \
    --workflow-id <workflow-id> \
    --event-id <event-id> \
    --reason "Reason for reset"
```

For example:

```bash
temporal workflow reset \
    --workflow-id my-background-check \
    --event-id 4 \
    --reason "Fixed non-deterministic code"
```

By default, the command resets the latest Workflow Execution in the `default` Namespace. Use `--run-id` to reset a
specific run. Use `--namespace` to specify a different Namespace:

```bash
temporal workflow reset \
    --workflow-id my-background-check \
    --event-id 4 \
    --reason "Fixed non-deterministic code" \
    --namespace my-namespace \
    --tls-cert-path /path/to/cert.pem \
    --tls-key-path /path/to/key.pem
```

Monitor the new Workflow Execution after resetting to ensure it completes successfully.

</TabItem>

</Tabs>

---

## Child Workflows - Java SDK

This page shows how to do the following:

- [Start a Child Workflow Execution](#start-child-workflow)
- [Set a Parent Close Policy](#parent-close-policy)

## Start a Child Workflow Execution {#start-child-workflow}

**How to start a Child Workflow Execution using the Java SDK.**

A [Child Workflow Execution](/child-workflows) is a Workflow Execution that is scheduled from within another Workflow using a Child Workflow API.

When using a Child Workflow API, Child Workflow related Events ([StartChildWorkflowExecutionInitiated](/references/events#startchildworkflowexecutioninitiated), [ChildWorkflowExecutionStarted](/references/events#childworkflowexecutionstarted), [ChildWorkflowExecutionCompleted](/references/events#childworkflowexecutioncompleted), etc...) are logged in the Workflow Execution Event History.

Always block progress until the [ChildWorkflowExecutionStarted](/references/events#childworkflowexecutionstarted) Event is logged to the Event History to ensure the Child Workflow Execution has started.
After that, Child Workflow Executions may be abandoned using the _Abandon_ [Parent Close Policy](/parent-close-policy) set in the Child Workflow Options.

To be sure that the Child Workflow Execution has started, first call the Child Workflow Execution method on the instance of Child Workflow future, which returns a different future.

Then get the value of an object that acts as a proxy for a result that is initially unknown, which is what waits until the Child Workflow Execution has spawned.

### Async Child Workflows

The first call to the Child Workflow stub must always be its Workflow method (method annotated with `@WorkflowMethod`).
Similar to Activities, invoking Child Workflow methods can be made synchronous or asynchronous by using `Async#function` or `Async#procedure`.
The synchronous call blocks until a Child Workflow method completes.
The asynchronous call returns a `Promise` which can be used to wait for the completion of the Child Workflow method, as in the following example:

```java
GreetingChild child = Workflow.newChildWorkflowStub(GreetingChild.class);
Promise<String> greeting = Async.function(child::composeGreeting, "Hello", name);
// ...
greeting.get()
```

To execute an untyped Child Workflow asynchronously, call `executeAsync` on the `ChildWorkflowStub`, as shown in the following example.

```java
//...
ChildWorkflowStub childUntyped =
    Workflow.newUntypedChildWorkflowStub(
        "GreetingChild", // your workflow type
        ChildWorkflowOptions.newBuilder().setWorkflowId("childWorkflow").build());

Promise<String> greeting =
    childUntyped.executeAsync(String.class, String.class, "Hello", name);
String result = greeting.get();
//...
```

The following examples show how to spawn a Child Workflow:

- Spawn a Child Workflow from a Workflow

  ```java
  // Child Workflow interface
  @WorkflowInterface
  public interface GreetingChild {
  @WorkflowMethod
  String composeGreeting(String greeting, String name);
  }
  // Child Workflow implementation not shown

  // Parent Workflow implementation
  public class GreetingWorkflowImpl implements GreetingWorkflow {

  @Override
  public String getGreeting(String name) {
      GreetingChild child = Workflow.newChildWorkflowStub(GreetingChild.class);

      // This is a blocking call that returns only after child has completed.
      return child.composeGreeting("Hello", name );
  }
  }
  ```

- Spawn two Child Workflows (with the same type) in parallel:

  ```java
  // Parent Workflow implementation
  public class GreetingWorkflowImpl implements GreetingWorkflow {

      @Override
      public String getGreeting(String name) {

          // Workflows are stateful, so a new stub must be created for each new child.
          GreetingChild child1 = Workflow.newChildWorkflowStub(GreetingChild.class);
          Promise<String> greeting1 = Async.function(child1::composeGreeting, "Hello", name);

          // Both children will run concurrently.
          GreetingChild child2 = Workflow.newChildWorkflowStub(GreetingChild.class);
          Promise<String> greeting2 = Async.function(child2::composeGreeting, "Bye", name);

          // Do something else here.
          ...
          return "First: " + greeting1.get() + ", second: " + greeting2.get();
      }
  }
  ```

- Send a Signal to a Child Workflow from the parent:

  ```java
  // Child Workflow interface
  @WorkflowInterface
  public interface GreetingChild {
      @WorkflowMethod
      String composeGreeting(String greeting, String name);

      @SignalMethod
      void updateName(String name);
  }

  // Parent Workflow implementation
  public class GreetingWorkflowImpl implements GreetingWorkflow {

      @Override
      public String getGreeting(String name) {
          GreetingChild child = Workflow.newChildWorkflowStub(GreetingChild.class);
          Promise<String> greeting = Async.function(child::composeGreeting, "Hello", name);
          child.updateName("Temporal");
          return greeting.get();
      }
  }
  ```

- Sending a Query to Child Workflows from within the parent Workflow code is not supported. However, you can send a Query to Child Workflows from Activities using `WorkflowClient`.

Related reads:

- [How to develop a Workflow Definition](/develop/java/core-application#develop-workflows)

- Java Workflow reference: [https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/package-summary.html](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/package-summary.html)

## Parent Close Policy {#parent-close-policy}

**How to set a Parent Close Policy for a Child Workflow using the Java SDK.**

A [Parent Close Policy](/parent-close-policy) determines what happens to a Child Workflow Execution if its Parent changes to a Closed status (Completed, Failed, or Timed Out).

The default Parent Close Policy option is set to terminate the Child Workflow Execution.

Set [Parent Close Policy](/parent-close-policy) on an instance of `ChildWorkflowOptions` using [`ChildWorkflowOptions.newBuilder().setParentClosePolicy`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/ChildWorkflowOptions.Builder.html).

- Type: `ChildWorkflowOptions.Builder`
- Default: `PARENT_CLOSE_POLICY_TERMINATE`

```java
 public void parentWorkflow() {
     ChildWorkflowOptions options =
        ChildWorkflowOptions.newBuilder()
            .setParentClosePolicy(ParentClosePolicy.PARENT_CLOSE_POLICY_ABANDON)
            .build();
     MyChildWorkflow child = Workflow.newChildWorkflowStub(MyChildWorkflow.class, options);
     Async.procedure(child::<workflowMethod>, <args>...);
     Promise<WorkflowExecution> childExecution = Workflow.getWorkflowExecution(child);
     // Wait for child to start
     childExecution.get()
}
```

In this example, we are:

1. Setting `ChildWorkflowOptions.ParentClosePolicy` to `ABANDON` when creating a Child Workflow stub.
2. Starting Child Workflow Execution asynchronously using `Async.function` or `Async.procedure`.
3. Calling `Workflow.getWorkflowExecution(…)` on the child stub.
4. Waiting for the `Promise` returned by `getWorkflowExecution` to complete.
   This indicates whether the Child Workflow started successfully (or failed).
5. Completing parent Workflow Execution asynchronously.

Steps 3 and 4 are needed to ensure that a Child Workflow Execution starts before the parent closes.
If the parent initiates a Child Workflow Execution and then completes immediately after, the Child Workflow will never execute.

---

## Continue-As-New - Java SDK

This page answers the following questions for Java developers:

- [What is Continue-As-New?](#what)
- [How to Continue-As-New?](#how)
- [When is it right to Continue-as-New?](#when)
- [How to test Continue-as-New?](#how-to-test)

## What is Continue-As-New? {#what}

[Continue-As-New](/workflow-execution/continue-as-new) lets a Workflow Execution close successfully and creates a new Workflow Execution.
You can think of it as a checkpoint when your Workflow gets too long or approaches certain scaling limits.

The new Workflow Execution is in the same [chain](/workflow-execution#workflow-execution-chain); it keeps the same Workflow Id but gets a new Run Id and a fresh Event History.
It also receives your Workflow's usual parameters.

## How to Continue-As-New using the Java SDK {#how}

First, design your Workflow parameters so that you can pass in the "current state" when you Continue-As-New into the next Workflow run.
This state is typically set to `None` for the original caller of the Workflow.

  
    View the source code
  {' '}
  in the context of the rest of the application code.

```java
class ClusterManagerInput {
  private final Optional<ClusterManagerState> state;
  private final boolean testContinueAsNew;
}

@WorkflowMethod
ClusterManagerResult run(ClusterManagerInput input);

````
The test hook in the above snippet is covered [below](#how-to-test).

Inside your Workflow, call the [`continueAsNew()`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#continueAsNew(io.temporal.workflow.ContinueAsNewOptions,java.lang.Object...)) function with the same type.
This stops the Workflow right away and starts a new one.

  
    View the source code
  {' '}
  in the context of the rest of the application code.

```java
Workflow.continueAsNew(
  new ClusterManagerInput(Optional.of(state), input.isTestContinueAsNew()));
````

### Considerations for Workflows with Message Handlers {#with-message-handlers}

If you use Updates or Signals, don't call Continue-as-New from the handlers.
Instead, wait for your handlers to finish in your main Workflow before you run `continueAsNew`.

## When is it right to Continue-as-New using the Java SDK? {#when}

Use Continue-as-New when your Workflow might hit [Event History Limits](/workflow-execution/event#event-history).

Temporal tracks your Workflow's progress against these limits to let you know when you should Continue-as-New.
Call `Workflow.getInfo().isContinueAsNewSuggested()` to check if it's time.

## How to test Continue-as-New using the Java SDK {#how-to-test}

Testing Workflows that naturally Continue-as-New may be time-consuming and resource-intensive.
Instead, add a test hook to check your Workflow's Continue-as-New behavior faster in automated tests.

For example, when `testContinueAsNew == true`, this sample creates a test-only variable called `maxHistoryLength` and sets it to a small value.
A helper method in the Workflow checks it each time it considers using Continue-as-New:

  
    View the source code
  {' '}
  in the context of the rest of the application code.

```java
private boolean shouldContinueAsNew() {
  if (Workflow.getInfo().isContinueAsNewSuggested()) {
    return true;
  }
  // This is just for ease-of-testing.  In production, we trust temporal to tell us when to
  // continue as new.
  if (maxHistoryLength > 0 && Workflow.getInfo().getHistoryLength() > maxHistoryLength) {
    return true;
  }
  return false;
}
```

---

## Converters and encryption - Java SDK

Temporal's security model is designed around client-side encryption of Payloads.
A client may encrypt Payloads before sending them to the server, and decrypt them after receiving them from the server.
This provides a high degree of confidentiality because the Temporal Server itself has absolutely no knowledge of the actual data.
It also gives implementers more power and more freedom regarding which client is able to read which data -- they can control access with keys, algorithms, or other security measures.

A Temporal developer adds client-side encryption of Payloads by providing a Custom Payload Codec to its Client.
Depending on business needs, a complete implementation of Payload Encryption may involve selecting appropriate encryption algorithms, managing encryption keys, restricting a subset of their users from viewing payload output, or a combination of these.

The server itself never adds encryption over Payloads.
Therefore, unless client-side encryption is implemented, Payload data will be persisted in non-encrypted form to the data store, and any Client that can make requests to a Temporal namespace (including the Temporal UI and CLI) will be able to read Payloads contained in Workflows.
When working with sensitive data, you should always implement Payload encryption.

## Custom Payload Codec in Java {#custom-payload-codec}

**How to create a custom Payload Codec using the Java SDK.**

Create a custom implementation of [`PayloadCodec`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/payload/codec/PayloadCodec.html) and use it in [`CodecDataConverter`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/common/converter/CodecDataConverter.html) to set a custom Data Converter.

The Payload Codec does byte-to-byte conversion and must be set with a Data Converter.

Define custom encryption/compression logic in your `encode` method and decryption/decompression logic in your `decode` method.

The following example from the [Java encryption sample](https://github.com/temporalio/samples-java/tree/main/core/src/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java) shows how to implement encryption and decryption logic on your payloads in your `encode` and `decode` methods.

```java
class YourCustomPayloadCodec implements PayloadCodec {

  static final ByteString METADATA_ENCODING =
      ByteString.copyFrom("binary/encrypted", StandardCharsets.UTF_8);

  private static final String CIPHER = "AES/GCM/NoPadding";

  // Define constants that you can add to your encoded Payload to create a new Payload.
  static final String METADATA_ENCRYPTION_CIPHER_KEY = "encryption-cipher";

  static final ByteString METADATA_ENCRYPTION_CIPHER =
      ByteString.copyFrom(CIPHER, StandardCharsets.UTF_8);

  static final String METADATA_ENCRYPTION_KEY_ID_KEY = "encryption-key-id";

  private static final Charset UTF_8 = StandardCharsets.UTF_8;

  // See the linked sample for details on the methods called here.
  @NotNull
  @Override
  public List<Payload> encode(@NotNull List<Payload> payloads) {
    return payloads.stream().map(this::encodePayload).collect(Collectors.toList());
  }

  @NotNull
  @Override
  public List<Payload> decode(@NotNull List<Payload> payloads) {
    return payloads.stream().map(this::decodePayload).collect(Collectors.toList());
  }

  private Payload encodePayload(Payload payload) {
    String keyId = getKeyId();
    SecretKey key = getKey(keyId);

    byte[] encryptedData;
    try {
      encryptedData = encrypt(payload.toByteArray(), key); // The encrypt method contains your custom encryption logic.
    } catch (Throwable e) {
      throw new DataConverterException(e);
    }
    // Apply metadata to the encoded Payload that you can verify in your decode method before decoding.
    // See the sample for details on the metadata values set.
    return Payload.newBuilder()
        .putMetadata(EncodingKeys.METADATA_ENCODING_KEY, METADATA_ENCODING)
        .putMetadata(METADATA_ENCRYPTION_CIPHER_KEY, METADATA_ENCRYPTION_CIPHER)
        .putMetadata(METADATA_ENCRYPTION_KEY_ID_KEY, ByteString.copyFromUtf8(keyId))
        .setData(ByteString.copyFrom(encryptedData))
        .build();
  }

  private Payload decodePayload(Payload payload) {
    // Verify the incoming encoded Payload metadata before applying decryption.
    if (METADATA_ENCODING.equals(
        payload.getMetadataOrDefault(EncodingKeys.METADATA_ENCODING_KEY, null))) {
      String keyId;
      try {
        keyId = payload.getMetadataOrThrow(METADATA_ENCRYPTION_KEY_ID_KEY).toString(UTF_8);
      } catch (Exception e) {
        throw new PayloadCodecException(e);
      }
      SecretKey key = getKey(keyId);
      byte[] plainData;
      Payload decryptedPayload;

      try {
        plainData = decrypt(payload.getData().toByteArray(), key); // The decrypt method contains your custom decryption logic.
        decryptedPayload = Payload.parseFrom(plainData);
        return decryptedPayload;
      } catch (Throwable e) {
        throw new PayloadCodecException(e);
      }
    } else {
      return payload;
    }
  }

  private String getKeyId() {
    // Currently there is no context available to vary which key is used.
    // Use a fixed key for all payloads.
    // This still supports key rotation as the key ID is recorded on payloads allowing
    // decryption to use a previous key.

    return "test-key-test-key-test-key-test!";
  }

  private SecretKey getKey(String keyId) {
    // Key must be fetched from KMS or other secure storage.
    // Hard coded here only for example purposes.
    return new SecretKeySpec(keyId.getBytes(UTF_8), "AES");
  }

  //...
}
```

**Set Data Converter to use custom Payload Codec**

Use `CodecDataConverter` with an instance of a Data Converter and the custom `PayloadCodec` in the `WorkflowClient` options that you use in your Worker process and to start your Workflow Executions.

For example, to set a custom `PayloadCodec` implementation with `DefaultDataConverter`, use the following code:

```java
WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
  // Client that can be used to start and signal Workflows
  WorkflowClient client =
      WorkflowClient.newInstance(
          service,
          WorkflowClientOptions.newBuilder()
              .setDataConverter(
                  new CodecDataConverter(
                      DefaultDataConverter.newDefaultInstance(),
                      Collections.singletonList(new YourCustomPayloadCodec()))) // Sets the custom Payload Codec created in the previous example with an instance of the default Data Converter.
              .build());
```

- Data **encoding** is performed by the client using the converters and codecs provided by Temporal or your custom implementation when passing input to the Temporal Cluster. For example, plain text input is usually serialized into a JSON object, and can then be compressed or encrypted.
- Data **decoding** may be performed by your application logic during your Workflows or Activities as necessary, but decoded Workflow results are never persisted back to the Temporal Cluster. Instead, they are stored encoded on the Cluster, and you need to provide an additional parameter when using the [temporal workflow show](/cli/workflow#show) command or when browsing the Web UI to view output.

For reference, see the [Encryption](https://github.com/temporalio/samples-java/tree/main/core/src/main/java/io/temporal/samples/encryptedpayloads) sample.

### Using a Codec Server

A Codec Server is an HTTP server that uses your custom Codec logic to decode your data remotely.
The Codec Server is independent of the Temporal Cluster and decodes your encrypted payloads through predefined endpoints.
You create, operate, and manage access to your Codec Server in your own environment.
The Temporal CLI and the Web UI in turn provide built-in hooks to call the Codec Server to decode encrypted payloads on demand.
Refer to the [Codec Server](/production-deployment/data-encryption) documentation for information on how to design and deploy a Codec Server.

For reference, see the [Codec server](https://github.com/temporalio/sdk-java/tree/master/temporal-remote-data-encoder) sample.

## Using custom Payload conversion {#custom-payload-conversion}

**How to do custom Payload conversion using the Java SDK.**

Temporal SDKs provide a [Payload Converter](/payload-converter) that can be customized to convert a custom data type to [Payload](/dataconversion#payload) and back.

Implementing custom Payload conversion is optional.
It is needed only if the [default Data Converter](/default-custom-data-converters#default-data-converter) does not support your custom values.

To support custom Payload conversion, create a [custom Payload Converter](/payload-converter#composite-data-converters) and configure the Data Converter to use it in your Client options.

The order in which your encoding Payload Converters are applied depend on the order given to the Data Converter.
You can set multiple encoding Payload Converters to run your conversions.
When the Data Converter receives a value for conversion, it passes through each Payload Converter in sequence until the converter that handles the data type does the conversion.

Payload Converters can be customized independently of a Payload Codec.
Temporal's Converter architecture looks like this:

<CaptionedImage
    src="/img/info/converter-architecture.png"
    title="Temporal converter architecture"
/>

Create a custom implementation of a [PayloadConverter](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/common/converter/PayloadConverter.html) interface and use the `withPayloadConverterOverrides` method to implement the custom object conversion with `DefaultDataConverter`.

`PayloadConverter` serializes and deserializes method parameters that need to be sent over the wire.
You can create a custom implementation of `PayloadConverter` for custom formats, as shown in the following example:

```java
/** Payload Converter specific to your custom object */
public class YourCustomPayloadConverter implements PayloadConverter {
 //...
  @Override
  public String getEncodingType() {
    return "json/plain"; // The encoding type determines which default conversion behavior to override.
  }

  @Override
  public Optional<Payload> toData(Object value) throws DataConverterException {
      // Add your convert-to logic here.
  }

  @Override
  public <T> T fromData(Payload content, Class<T> valueClass, Type valueType)
      throws DataConverterException {
    // Add your convert-from logic here.
  }
//...
}
```

You can also use [specific implementation classes](https://www.javadoc.io/static/io.temporal/temporal-sdk/1.18.1/io/temporal/common/converter/package-summary.html) provided in the Java SDK.

For example, to create a custom `JacksonJsonPayloadConverter`, use the following:

```java
//...
private static JacksonJsonPayloadConverter yourCustomJacksonJsonPayloadConverter() {
  ObjectMapper objectMapper = new ObjectMapper();
  // Add your custom logic here.
  return new JacksonJsonPayloadConverter(objectMapper);
}
//...
```

To set your custom Payload Converter, use it with [withPayloadConverterOverrides](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/common/converter/DefaultDataConverter.html#withPayloadConverterOverrides(io.temporal.common.converter.PayloadConverter...)) with a new instance of `DefaultDataConverter` in your `WorkflowClient` options that you use in your Worker process and to start your Workflow Executions.

The following example shows how to set a custom `YourCustomPayloadConverter` Payload Converter.

```java
//...
DefaultDataConverter ddc =
        DefaultDataConverter.newDefaultInstance()
            .withPayloadConverterOverrides(new YourCustomPayloadConverter());

    WorkflowClientOptions workflowClientOptions =
        WorkflowClientOptions.newBuilder().setDataConverter(ddc).build();
//...
```

---

## Core application - Java SDK

This page shows how to do the following:

- [Develop a Workflow Definition](#develop-workflows)
- [Develop a basic Activity](#develop-activities)
- [Start an Activity Execution](#activity-execution)
- [Run a Development Worker](#run-a-dev-worker)

## Develop a Workflow Definition {#develop-workflows}

**How to develop a Workflow Definition using the Java SDK.**

Workflows are the fundamental unit of a Temporal Application, and it all starts with the development of a [Workflow Definition](/workflow-definition).

In the Temporal Java SDK programming model, a Workflow Definition comprises a Workflow interface annotated with `@WorkflowInterface` and a Workflow implementation that implements the Workflow interface.

The Workflow interface is a Java interface and is annotated with `@WorkflowInterface`.
Each Workflow interface must have only one method annotated with `@WorkflowMethod`.

```java
// Workflow interface
@WorkflowInterface
public interface YourWorkflow {

    @WorkflowMethod
    String yourWFMethod(Arguments args);
}
```

However, when using dynamic Workflows, do not specify a `@WorkflowMethod`, and implement the `DynamicWorkflow` directly in the Workflow implementation code.

The `@WorkflowMethod` identifies the method that is the starting point of the Workflow Execution.
The Workflow Execution completes when this method completes.

You can create [interface inheritance hierarchies](#interface-inheritance) to reuse components across other Workflow interfaces.
The interface inheritance approach does not apply to `@WorkflowMethod` annotations.

A Workflow implementation implements a Workflow interface.

```java
// Define the Workflow implementation which implements our getGreeting Workflow method.
  public static class GreetingWorkflowImpl implements GreetingWorkflow {
      ...
    }
  }
```

To call Activities in your Workflow, call the Activity implementation.

Use `ExternalWorkflowStub` to start or send Signals from within a Workflow to other running Workflow Executions.

You can also invoke other Workflows as Child Workflows with `Workflow.newChildWorkflowStub()` or `Workflow.newUntypedChildWorkflowStub()` within a Workflow Definition.

### Workflow interface inheritance {#interface-inheritance}

Workflow interfaces can form inheritance hierarchies.
It may be useful for creating reusable components across multiple
Workflow interfaces.
For example imagine a UI or CLI button that allows a `retryNow` Signal on any Workflow. To implement this feature you can redesign an interface like the following:

```java
public interface Retryable {
    @SignalMethod
    void retryNow();
}

@WorkflowInterface
public interface FileProcessingWorkflow extends Retryable {

    @WorkflowMethod
    String processFile(Arguments args);

    @QueryMethod(name="history")
    List<String> getHistory();

    @QueryMethod
    String getStatus();

    @SignalMethod
    void abandon();
}
```

Then some other Workflow interface can extend just `Retryable`, for example:

```java
@WorkflowInterface
public interface MediaProcessingWorkflow extends Retryable {

    @WorkflowMethod
    String processBlob(Arguments args);
}
```

Now if we have two running Workflows, one that implements the `FileProcessingWorkflow` interface and another that implements the `MediaProcessingWorkflow` interface, we can Signal to both using their common interface and knowing their WorkflowIds, for example:

```java
Retryable r1 = client.newWorkflowStub(Retryable.class, firstWorkflowId);
Retryable r2 = client.newWorkflowStub(Retryable.class, secondWorkflowId);
r1.retryNow();
r2.retryNow();
```

The same technique can be used to query Workflows using a base Workflow interface.

Note that this approach does not apply to `@WorkflowMethod` annotations, meaning that when using a base interface, it should not include any `@WorkflowMethod` methods.
To illustrate this, lets' say that we define the following **invalid** code:

```java
// INVALID CODE!
public interface BaseWorkflow {
    @WorkflowMethod
    void retryNow();
}

@WorkflowInterface
public interface Workflow1 extends BaseWorkflow {}

@WorkflowInterface
public interface Workflow2 extends BaseWorkflow {}
```

Any attempt to register both implementations with the Worker will fail.
Let's say that we have:

```java
worker.registerWorkflowImplementationTypes(
        Workflow1Impl.class, Workflow2Impl.class);
```

This registration will fail with:

```text
java.lang.IllegalStateException: BaseWorkflow workflow type is already registered with the worker
```

### Define Workflow parameters {#workflow-parameters}

**How to define Workflow parameters using the Java SDK.**

Temporal Workflows may have any number of custom parameters.
However, we strongly recommend that objects are used as parameters, so that the object's individual fields may be altered without breaking the signature of the Workflow.
All Workflow Definition parameters must be serializable.

A method annotated with `@WorkflowMethod` can have any number of parameters.

We recommend passing a single parameter that contains all the input fields to allow for adding fields in a backward-compatible manner.

Note that all inputs should be serializable by the default Jackson JSON Payload Converter.

You can create a custom object and pass it to the Workflow method, as shown in the following example.

```java
//...
@WorkflowInterface
public interface YourWorkflow {
    @WorkflowMethod
    String yourWFMethod(CustomObj customobj);
// ...
}
```

### Define Workflow return parameters {#workflow-return-values}

**How to define Workflow return parameters using the Java SDK.**

Workflow return values must also be serializable.
Returning results, returning errors, or throwing exceptions is fairly idiomatic in each language that is supported.
However, Temporal APIs that must be used to get the result of a Workflow Execution will only ever receive one of either the result or the error.

Workflow method arguments and return values must be serializable and deserializable using the provided [`DataConverter`](https://www.javadoc.io/static/io.temporal/temporal-sdk/1.17.0/io/temporal/common/converter/DataConverter.html).

The `execute` method for `DynamicWorkflow` can return type Object.
Ensure that your Client can handle an Object type return or is able to convert the Object type response.

Related references:

- [Data Converter](/dataconversion)
- Java DataConverter reference: [https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/common/converter/DataConverter.html](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/common/converter/DataConverter.html)

### Customize your Workflow Type {#workflow-type}

**How to customize your Workflow Type using the Java SDK.**

Workflows have a Type that are referred to as the Workflow name.

The following examples demonstrate how to set a custom name for your Workflow Type.

The Workflow Type defaults to the short name of the Workflow interface.
In the following example, the Workflow Type defaults to `NotifyUserAccounts`.

```java
  @WorkflowInterface

  public interface NotifyUserAccounts {
    @WorkflowMethod
    void notify(String[] accountIds);
}
```

To overwrite this default naming and assign a custom Workflow Type, use the `@WorkflowMethod` annotation with the `name` parameter.
In the following example, the Workflow Type is set to `your-workflow`.

```java
@WorkflowInterface

  public interface NotifyUserAccounts {
  @WorkflowMethod(name = "your-workflow")
  void notify(String[] accountIds);
  }
```

When you set the Workflow Type this way, the value of the `name` parameter does not have to start with an uppercase letter.

### Workflow logic requirements {#workflow-logic-requirements}

Workflow logic is constrained by [deterministic execution requirements](/workflow-definition#deterministic-constraints).
Therefore, each language is limited to the use of certain idiomatic techniques.
However, each Temporal SDK provides a set of APIs that can be used inside your Workflow to interact with external (to the Workflow) application code.

When defining Workflows using the Temporal Java SDK, the Workflow code must be written to execute effectively once and to completion.

The following constraints apply when writing Workflow Definitions:

- Do not use mutable global variables in your Workflow implementations.
  This will ensure that multiple Workflow instances are fully isolated.
- Your Workflow code must be deterministic.
  Do not call non-deterministic functions (such as non-seeded random or `UUID.randomUUID()`) directly from the Workflow code.
  The Temporal SDK provides specific API for calling non-deterministic code in your Workflows.
- Do not use programming language constructs that rely on system time.
  For example, only use `Workflow.currentTimeMillis()` to get the current time inside a Workflow.
- Do not use native Java `Thread` or any other multi-threaded classes like `ThreadPoolExecutor`.
  Use `Async.function` or `Async.procedure`, provided by the Temporal SDK, to execute code asynchronously.
- Do not use synchronization, locks, or other standard Java blocking concurrency-related classes besides those provided by the Workflow class.
  There is no need for explicit synchronization because multi-threaded code inside a Workflow is executed one thread at a time and under a global lock.
  - Call `Workflow.sleep` instead of `Thread.sleep`.
  - Use `Promise` and `CompletablePromise` instead of `Future` and `CompletableFuture`.
  - Use `WorkflowQueue` instead of `BlockingQueue`.
- Use `Workflow.getVersion` when making any changes to the Workflow code.
  Without this, any deployment of updated Workflow code might break already running Workflows.
- Do not access configuration APIs directly from a Workflow because changes in the configuration might affect a Workflow Execution path.
  Pass it as an argument to a Workflow function or use an Activity to load it.
- Use `DynamicWorkflow` when you need a default Workflow that can handle all Workflow Types that are not registered with a Worker.
  A single implementation can implement a Workflow Type which by definition is dynamically loaded from some external source.
  All standard `WorkflowOptions` and determinism rules apply to Dynamic Workflow implementations.

Java Workflow reference: [https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/package-summary.html](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/package-summary.html)

## Develop a basic Activity {#develop-activities}

**How to develop a basic Activity using the Java SDK.**

One of the primary things that Workflows do is orchestrate the execution of Activities.
An Activity is a normal function or method execution that's intended to execute a single, well-defined action (either short or long-running), such as querying a database, calling a third-party API, or transcoding a media file.
An Activity can interact with world outside the Temporal Platform or use a Temporal Client to interact with a Temporal Service.
For the Workflow to be able to execute the Activity, we must define the [Activity Definition](/activity-definition).

An [Activity Definition](/activities) is a combination of the Temporal Java SDK [Activity](https://www.javadoc.io/static/io.temporal/temporal-sdk/0.19.0/io/temporal/activity/Activity.html) Class implementing a specially annotated interface.

An Activity interface is annotated with `@ActivityInterface` and an Activity implementation implements this Activity interface.
To handle Activity types that do not have an explicitly registered handler, you can directly implement a dynamic Activity.

```java
@ActivityInterface
public interface GreetingActivities {
    String composeGreeting(String greeting, String language);
}
```

Each method defined in the Activity interface defines a separate Activity method.
You can annotate each method in the Activity interface with the `@ActivityMethod` annotation, but this is completely optional.
The following example uses the `@ActivityMethod` annotation for the method defined in the previous example.

```java
@ActivityInterface
public interface GreetingActivities {
    @ActivityMethod
    String composeGreeting(String greeting, String language);
}
```

An Activity implementation is a Java class that implements an Activity annotated interface.

```java
// Implementation for the GreetingActivities interface example from in the previous section
 static class GreetingActivitiesImpl implements GreetingActivities {
    @Override
    public String composeGreeting(String greeting, String name) {
      return greeting + " " + name + "!";
    }
  }
```

### Define Activity parameters {#activity-parameters}

**How to define Activity parameters using the Java SDK.**

There is no explicit limit to the total number of parameters that an [Activity Definition](/activity-definition) may support.
However, there is a limit to the total size of the data that ends up encoded into a gRPC message Payload.

A single argument is limited to a maximum size of 2 MB.
And the total size of a gRPC message, which includes all the arguments, is limited to a maximum of 4 MB.

Also, keep in mind that all Payload data is recorded in the [Workflow Execution Event History](/workflow-execution/event#event-history) and large Event Histories can affect Worker performance.
This is because the entire Event History could be transferred to a Worker Process with a [Workflow Task](/tasks#workflow-task).

{/* TODO link to gRPC limit section when available */}

Some SDKs require that you pass context objects, others do not.
When it comes to your application data—that is, data that is serialized and encoded into a Payload—we recommend that you use a single object as an argument that wraps the application data passed to Activities.
This is so that you can change what data is passed to the Activity without breaking a function or method signature.

An Activity interface can have any number of parameters.
All inputs should be serializable by the default Jackson JSON Payload Converter.

When implementing Activities, be mindful of the amount of data that you transfer using the Activity invocation parameters or return values as these are recorded in the Workflow Execution Events History.
Large Events Histories can adversely impact performance.

You can create a custom object, and pass it to the Activity interface, as shown in the following example.

```java
@ActivityInterface
public interface YourActivities {
    String getCustomObject(CustomObj customobj);
    void sendCustomObject(CustomObj customobj, String abc);
}
```

The `execute` method in the dynamic Activity interface implementation takes in `EncodedValues` that are inputs to the Activity Execution, as shown in the following example.

```java
// Dynamic Activity implementation
 public static class DynamicActivityImpl implements DynamicActivity {
   @Override
   public Object execute(EncodedValues args) {
     String activityType = Activity.getExecutionContext().getInfo().getActivityType();
     return activityType
         + ": "
         + args.get(0, String.class)
         + " "
         + args.get(1, String.class)
         + " from: "
         + args.get(2, String.class);
   }
 }
```

For more details, see [Dynamic Activity Reference](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/activity/DynamicActivity.html).

### Define Activity return values {#activity-return-values}

**How to define Activity return values using the Java SDK.**

All data returned from an Activity must be serializable.

Activity return values are subject to payload size limits in Temporal. The default payload size limit is 2MB, and there is a hard limit of 4MB for any gRPC message size in the Event History transaction ([see Cloud limits here](https://docs.temporal.io/cloud/limits#per-message-grpc-limit)). Keep in mind that all return values are recorded in a [Workflow Execution Event History](/workflow-execution/event#event-history).

Activity return values must be serializable and deserializable by the provided [`DataConverter`](https://www.javadoc.io/static/io.temporal/temporal-sdk/1.17.0/io/temporal/common/converter/DataConverter.html).

The `execute` method for `DynamicActivity` can return type Object.
Ensure that your Workflow or Client can handle an Object type return or is able to convert the Object type response.

- [Data Converter](/dataconversion)
- Java DataConverter reference: [https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/common/converter/DataConverter.html](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/common/converter/DataConverter.html)

### Customize your Activity Type {#activity-type}

**How to customize your Activity Type using the Java SDK.**

Each Activity has a Type, which may also be referred to as the Activity 'name'.
This name appears in the Workflow Execution Event History in the Summary tab for each Activity Task.
The name lets you identify Activity Types called during the Execution.

Custom Activity Type names prevent name collisions across interfaces and Workflows.
They offer descriptive Activity method names without concerns about re-using those names elsewhere in your project.
They also support code management, especially in larger projects with many Activities.
For example, you might use a prefix to group related activities together.
Custom names also distinguish keys for gathering metrics without name conflicts.

The following examples show how to set custom names for your Activity Type.

**Default behavior**

By default, an Activity Type is the method name with the first letter capitalized:

```java
@ActivityInterface
public interface GreetingActivities {
    String sendMessage(String input);

    @ActivityMethod
    String composeGreeting(String greeting, String language);
}
```

- Method Name: `sendMessage`
- Activity Type: `SendMessage`
- Method Name: `composeGreeting`
- Activity Type: `ComposeGreeting`

**Custom Prefix**

Using the `namePrefix` parameter in the `@ActivityInterface` annotation adds a prefix to each Activity Type name mentioned in the interface, unless the prefix is specifically overridden:

```java
@ActivityInterface(namePrefix = "Messaging_")
public interface GreetingActivities {
    String sendMessage(String input);

    @ActivityMethod
    String composeGreeting(String greeting, String language);
}
```

- Method Name: `sendMessage`
- Activity Type: `Messaging_SendMessage`
- Method Name: `composeGreeting`
- Activity Type: `Messaging_ComposeGreeting`

The Activity Type is capitalized, even when using a prefix.

**Custom Name**

To override the default name and any inherited prefixes, use the `name` parameter in the `@ActivityMethod` annotation:

```java
@ActivityInterface(namePrefix = "Messaging_")
public interface GreetingActivities {
    String sendMessage(String input);

    @ActivityMethod
    String composeGreeting(String greeting, String language);
    @ActivityMethod(name = "farewell")
    String composeFarewell(String farewell, String language);
}
```

Using the `name` parameter won't automatically capitalize the result:

- Method Name: `sendMessage`
- Activity Type: `Messaging_SendMessage`
- Method Name: `composeGreeting`
- Activity Type: `Messaging_ComposeGreeting`
- Method Name: `composeFarewell`
- Activity Type: `farewell`

Be cautious with names that contain special characters, as these can be used as metric tags.
Systems such as Prometheus may ignore metrics with tags using unsupported characters.

## Start an Activity Execution {#activity-execution}

**How to start an Activity Execution using the Java SDK.**

Calls to spawn [Activity Executions](/activity-execution) are written within a [Workflow Definition](/workflow-definition).
The call to spawn an Activity Execution generates the [ScheduleActivityTask](/references/commands#scheduleactivitytask) Command.
This results in the set of three [Activity Task](/tasks#activity-task) related Events ([ActivityTaskScheduled](/references/events#activitytaskscheduled), [ActivityTaskStarted](/references/events#activitytaskstarted), and ActivityTask[Closed])in your Workflow Execution Event History.

A single instance of the Activities implementation is shared across multiple simultaneous Activity invocations.
Activity implementation code should be _idempotent_.

The values passed to Activities through invocation parameters or returned through a result value are recorded in the Execution history.
The entire Execution history is transferred from the Temporal service to Workflow Workers when a Workflow state needs to recover.
A large Execution history can thus adversely impact the performance of your Workflow.

Therefore, be mindful of the amount of data you transfer through Activity invocation parameters or Return Values.
Otherwise, no additional limitations exist on Activity implementations.

Activities are remote procedure calls that must be invoked from within a Workflow using `ActivityStub`.
Activities are not executable on their own. You cannot start an Activity Execution by itself.

Note that before an Activity Execution is invoked:

- Activity options (either [`setStartToCloseTimeout`](/encyclopedia/detecting-activity-failures#start-to-close-timeout) or [`ScheduleToCloseTimeout`](/encyclopedia/detecting-activity-failures#schedule-to-close-timeout) are required) must be set for the Activity.
  For details, see [How to set Activity timeouts](/develop/java/failure-detection#activity-timeouts).
- The Activity must be registered with a Worker.
  See [Worker Program](#run-a-dev-worker)
- Activity code must be thread-safe.

Activities should only be instantiated using stubs from within a Workflow.
An `ActivityStub` returns a client-side stub that implements an Activity interface.
You can invoke Activities using `Workflow.newActivityStub`(type-safe) or `Workflow.newUntypedActivityStub` (untyped).

Calling a method on the Activity interface schedules the Activity invocation with the Temporal service, and generates an [`ActivityTaskScheduled` Event](/references/events#activitytaskscheduled).

Activities can be invoked synchronously or asynchronously.

**Invoking Activities Synchronously**

In the following example, we use the type-safe `Workflow.newActivityStub` within the "FileProcessingWorkflow" Workflow implementation to create a client-side stub of the `FileProcessingActivities` class. We also define `ActivityOptions` and set `setStartToCloseTimeout` option to one hour.

```java
public class FileProcessingWorkflowImpl implements FileProcessingWorkflow {

    private final FileProcessingActivities activities;

    public FileProcessingWorkflowImpl() {
        this.activities = Workflow.newActivityStub(
                FileProcessingActivities.class,
                ActivityOptions.newBuilder()
                        .setStartToCloseTimeout(Duration.ofHours(1))
                        .build());
    }

    @Override
    public void processFile(Arguments args) {
        String localName = null;
        String processedName = null;
        try {
            localName = activities.download(args.getSourceBucketName(), args.getSourceFilename());
            processedName = activities.processFile(localName);
            activities.upload(args.getTargetBucketName(), args.getTargetFilename(), processedName);
        } finally {
            if (localName != null) {
                activities.deleteLocalFile(localName);
            }
            if (processedName != null) {
                activities.deleteLocalFile(processedName);
            }
        }
    }
    // ...
}
```

A Workflow can have multiple Activity stubs. Each Activity stub can have its own `ActivityOptions` defined.
The following example shows a Workflow implementation with two typed Activity stubs.

```java
public FileProcessingWorkflowImpl() {
    ActivityOptions options1 = ActivityOptions.newBuilder()
             .setTaskQueue("taskQueue1")
             .setStartToCloseTimeout(Duration.ofMinutes(10))
             .build();
    this.store1 = Workflow.newActivityStub(FileProcessingActivities.class, options1);

    ActivityOptions options2 = ActivityOptions.newBuilder()
             .setTaskQueue("taskQueue2")
             .setStartToCloseTimeout(Duration.ofMinutes(5))
             .build();
    this.store2 = Workflow.newActivityStub(FileProcessingActivities.class, options2);
}
```

To invoke Activities inside Workflows without referencing the interface it implements, use an untyped Activity stub `Workflow.newUntypedActivityStub`.
This is useful when the Activity type is not known at compile time, or to invoke Activities implemented in different programming languages.

```java
   // Workflow code
    ActivityOptions activityOptions =
        ActivityOptions.newBuilder()
        .setStartToCloseTimeout(Duration.ofSeconds(3))
        .setTaskQueue("simple-queue-node")
        .build();

    ActivityStub activity = Workflow.newUntypedActivityStub(activityOptions);
    activity.execute("ComposeGreeting", String.class, "Hello World", "Spanish");
```

**Invoking Activities Asynchronously**

Sometimes Workflows need to perform certain operations in parallel.
The Temporal Java SDK provides the `Async` class which includes static methods used to invoke any Activity asynchronously.
The calls return a result of type `Promise` which is similar to the Java `Future` and `CompletionStage`.
When invoking Activities, use `Async.function` for Activities that return a result, and `Async.procedure` for Activities that return void.

In the following asynchronous Activity invocation, the method reference is passed to `Async.function` followed by Activity arguments.

```java
Promise<String> localNamePromise = Async.function(activities::download, sourceBucket, sourceFile);
```

The following example shows how to call two Activity methods, "download" and "upload", in parallel on multiple files.

```java
  public void processFile(Arguments args) {
    List<Promise<String>> localNamePromises = new ArrayList<>();
    List<String> processedNames = null;
    try {
      // Download all files in parallel.
      for (String sourceFilename : args.getSourceFilenames()) {
        Promise<String> localName =
            Async.function(activities::download, args.getSourceBucketName(), sourceFilename);
        localNamePromises.add(localName);
      }
      List<String> localNames = new ArrayList<>();
      for (Promise<String> localName : localNamePromises) {
        localNames.add(localName.get());
      }
      processedNames = activities.processFiles(localNames);

      // Upload all results in parallel.
      List<Promise<Void>> uploadedList = new ArrayList<>();
      for (String processedName : processedNames) {
        Promise<Void> uploaded =
            Async.procedure(
                activities::upload,
                args.getTargetBucketName(),
                args.getTargetFilename(),
                processedName);
        uploadedList.add(uploaded);
      }
      // Wait for all uploads to complete.
      Promise.allOf(uploadedList).get();
    } finally {
      for (Promise<String> localNamePromise : localNamePromises) {
        // Skip files that haven't completed downloading.
        if (localNamePromise.isCompleted()) {
          activities.deleteLocalFile(localNamePromise.get());
        }
      }
      if (processedNames != null) {
        for (String processedName : processedNames) {
          activities.deleteLocalFile(processedName);
        }
      }
    }
  }
```

**Activity Execution Context**

`ActivityExecutionContext` is a context object passed to each Activity implementation by default.
You can access it in your Activity implementations via `Activity.getExecutionContext()`.

It provides getters to access information about the Workflow that invoked the Activity.
Note that the Activity context information is stored in a thread-local variable.
Therefore, calls to `getExecutionContext()` succeed only within the thread that invoked the Activity function.

Following is an example of using the `ActivityExecutionContext`:

```java
public class FileProcessingActivitiesImpl implements FileProcessingActivities {

  @Override
  public String download(String bucketName, String remoteName, String localName) {

    ActivityExecutionContext ctx = Activity.getExecutionContext();
    ActivityInfo info = ctx.getInfo();

    log.info("namespace=" +  info.getActivityNamespace());
    log.info("workflowId=" + info.getWorkflowId());
    log.info("runId=" + info.getRunId());
    log.info("activityId=" + info.getActivityId());
    log.info("activityTimeout=" + info.getStartToCloseTimeout();

    return downloadFileFromS3(bucketName, remoteName, localDirectory + localName);
  }
    ...
}
```

For details on getting the results of an Activity Execution, see [Activity Execution Result](#activity-execution-result).

### Set required Activity Timeouts {#required-timeout}

**How to set required Activity Timeouts using the Java SDK.**

Activity Execution semantics rely on several parameters.
The only required value that needs to be set is either a [Schedule-To-Close Timeout](/encyclopedia/detecting-activity-failures#schedule-to-close-timeout) or a [Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout).
These values are set in the Activity Options.

Set your Activity Timeout from the [`ActivityOptions.Builder`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/activity/ActivityOptions.Builder.html) class.

Available timeouts are:

- ScheduleToCloseTimeout()
- ScheduleToStartTimeout()
- StartToCloseTimeout()

You can set Activity Options using an `ActivityStub` within a Workflow implementation, or per-Activity using `WorkflowImplementationOptions` within a Worker.

The following uses `ActivityStub`.

```java
GreetingActivities activities = Workflow.newActivityStub(GreetingActivities.class,
                ActivityOptions.newBuilder()
                        .setScheduleToCloseTimeout(Duration.ofSeconds(5))
                        // .setStartToCloseTimeout(Duration.ofSeconds(2)
                        // .setScheduletoCloseTimeout(Duration.ofSeconds(20))
                        .build());
```

The following uses `WorkflowImplementationOptions`.

```java
WorkflowImplementationOptions options =
            WorkflowImplementationOptions.newBuilder()
                    .setActivityOptions(
                            ImmutableMap.of(
                                    "GetCustomerGreeting",
                                    // Set Activity Execution timeout
                                    ActivityOptions.newBuilder()
                                        .setScheduleToCloseTimeout(Duration.ofSeconds(5))
                                        // .setStartToCloseTimeout(Duration.ofSeconds(2))
                                        // .setScheduleToStartTimeout(Duration.ofSeconds(5))
                                        .build()))
                    .build();
```

:::note

If you define options per-Activity Type options with `WorkflowImplementationOptions.setActivityOptions()`, setting them again specifically with `ActivityStub` in a Workflow will override this setting.

:::

### Java ActivityOptions reference {#activity-options-reference}

Use [`ActivityOptions`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/activity/ActivityOptions.Builder.html) to configure how to invoke an Activity Execution.

You can set Activity Options using an `ActivityStub` within a Workflow implementation, or per-Activity using `WorkflowImplementationOptions` within a Worker.
Note that if you define options per-Activity Type options with `WorkflowImplementationOptions.setActivityOptions()`, setting them again specifically with `ActivityStub` in a Workflow will override this setting.

The following table lists all `ActivityOptions` that can be configured for an Activity invocation.

| Option                                                 | Required                                           | Type                     |
| ------------------------------------------------------ | -------------------------------------------------- | ------------------------ |
| [`setScheduleToCloseTimeout`](#scheduletoclosetimeout) | Yes (if `StartToCloseTimeout` is not specified)    | Duration                 |
| [`setScheduleToStartTimeout`](#scheduletostarttimeout) | No                                                 | Duration                 |
| [`setStartToCloseTimeout`](#starttoclosetimeout)       | Yes (if `ScheduleToCloseTimeout` is not specified) | Duration                 |
| [`setHeartbeatTimeout`](#heartbeattimeout)             | No                                                 | Duration                 |
| [`setTaskQueue`](#taskqueue)                           | No                                                 | String                   |
| [`setRetryOptions`](#retryoptions)                     | No                                                 | RetryOptions             |
| [`setCancellationType`](#setcancellationtype)          | No                                                 | ActivityCancellationType |

#### ScheduleToCloseTimeout

To set a [Schedule-To-Close Timeout](/encyclopedia/detecting-activity-failures#schedule-to-close-timeout), use [`ActivityOptions.newBuilder.setScheduleToCloseTimeout​`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/activity/ActivityOptions.Builder.html).

This or `StartToCloseTimeout` must be set.

- Type: `Duration`
- Default: Unlimited.
  Note that if `WorkflowRunTimeout` and/or `WorkflowExecutionTimeout` are defined in the Workflow, all Activity retries will stop when either or both of these timeouts are reached.

You can set Activity Options using an `ActivityStub` within a Workflow implementation, or per-Activity using `WorkflowImplementationOptions` within a Worker.
Note that if you define options per-Activity Type options with `WorkflowImplementationOptions.setActivityOptions()`, setting them again specifically with `ActivityStub` in a Workflow will override this setting.

- With `ActivityStub`

  ```java
  GreetingActivities activities = Workflow.newActivityStub(GreetingActivities.class,
                  ActivityOptions.newBuilder()
                          .setScheduleToCloseTimeout(Duration.ofSeconds(5))
                          .build());
  ```

- With `WorkflowImplementationOptions`

  ```java
  WorkflowImplementationOptions options =
              WorkflowImplementationOptions.newBuilder()
                      .setActivityOptions(
                              ImmutableMap.of(
                                      "GetCustomerGreeting",
                                      ActivityOptions.newBuilder()
                                          .setScheduleToCloseTimeout(Duration.ofSeconds(5))
                                          .build()))
                      .build();
  ```

#### ScheduleToStartTimeout

To set a [Schedule-To-Start Timeout](/encyclopedia/detecting-activity-failures#schedule-to-start-timeout), use [`ActivityOptions.newBuilder.setScheduleToStartTimeout​`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/activity/ActivityOptions.Builder.html).

- Type: `Duration`
- Default: Unlimited. This timeout is non-retryable.

You can set Activity Options using an `ActivityStub` within a Workflow implementation, or per-Activity using `WorkflowImplementationOptions` within a Worker.
Note that if you define options per-Activity Type options with `WorkflowImplementationOptions.setActivityOptions()`, setting them again specifically with `ActivityStub` in a Workflow will override this setting.

- With `ActivityStub`

  ```java
  GreetingActivities activities = Workflow.newActivityStub(GreetingActivities.class,
                  ActivityOptions.newBuilder()
                          .setScheduleToStartTimeout(Duration.ofSeconds(5))
                          // note that either StartToCloseTimeout or ScheduleToCloseTimeout are
                          // required when setting Activity options.
                          .setScheduletoCloseTimeout(Duration.ofSeconds(20))
                          .build());
  ```

- With `WorkflowImplementationOptions`

  ```java
  WorkflowImplementationOptions options =
             WorkflowImplementationOptions.newBuilder()
                      .setActivityOptions(
                              ImmutableMap.of(
                                "GetCustomerGreeting",
                                ActivityOptions.newBuilder()
                                    .setScheduleToStartTimeout(Duration.ofSeconds(5))
                                    .build()))
                      .build();
  ```

#### StartToCloseTimeout

To set a [Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout), use [`ActivityOptions.newBuilder.setStartToCloseTimeout​`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/activity/ActivityOptions.Builder.html).

This or `ScheduleToClose` must be set.

- Type: `Duration`
- Default: Defaults to [`ScheduleToCloseTimeout`](#scheduletoclosetimeout) value

You can set Activity Options using an `ActivityStub` within a Workflow implementation, or per-Activity using `WorkflowImplementationOptions` within a Worker.
Note that if you define options per-Activity Type options with `WorkflowImplementationOptions.setActivityOptions()`, setting them again specifically with `ActivityStub` in a Workflow will override this setting.

- With `ActivityStub`

  ```java
  GreetingActivities activities = Workflow.newActivityStub(GreetingActivities.class,
              ActivityOptions.newBuilder()
                      .setStartToCloseTimeout(Duration.ofSeconds(2))
                      .build());
  ```

- With `WorkflowImplementationOptions`

  ```java
  WorkflowImplementationOptions options =
              WorkflowImplementationOptions.newBuilder()
                      .setActivityOptions(
                              ImmutableMap.of(
                                "EmailCustomerGreeting",
                                      ActivityOptions.newBuilder()
                                            // Set Activity Execution timeout (single run)
                                            .setStartToCloseTimeout(Duration.ofSeconds(2))
                                            .build()))
                      .build();
  ```

#### HeartbeatTimeout

To set a [Heartbeat Timeout](/encyclopedia/detecting-activity-failures#heartbeat-timeout), use [`ActivityOptions.newBuilder.setHeartbeatTimeout`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/activity/ActivityOptions.Builder.html).

- Type: `Duration`
- Default: None

You can set Activity Options using an `ActivityStub` within a Workflow implementation, or per-Activity using `WorkflowImplementationOptions` within a Worker.
Note that if you define options per-Activity Type options with `WorkflowImplementationOptions.setActivityOptions()`, setting them again specifically with `ActivityStub` in a Workflow will override this setting.

- With `ActivityStub`

  ```java
  private final GreetingActivities activities =
      Workflow.newActivityStub(
          GreetingActivities.class,
          ActivityOptions.newBuilder()
              // note that either StartToCloseTimeout or ScheduleToCloseTimeout are
              // required when setting Activity options.
              .setStartToCloseTimeout(Duration.ofSeconds(5))
              .setHeartbeatTimeout(Duration.ofSeconds(2))
              .build());
  ```

- With `WorkflowImplementationOptions`

  ```java
  WorkflowImplementationOptions options =
              WorkflowImplementationOptions.newBuilder()
                      .setActivityOptions(
                              ImmutableMap.of(
                                "EmailCustomerGreeting",
                                      ActivityOptions.newBuilder()
                                          // note that either StartToCloseTimeout or ScheduleToCloseTimeout are
                                          // required when setting Activity options.
                                            .setStartToCloseTimeout(Duration.ofSeconds(5))
                                            .setHeartbeatTimeout(Duration.ofSeconds(2))
                                            .build()))
                      .build();
  ```

#### TaskQueue

- Type: `String`
- Default: Defaults to the Task Queue that the Workflow was started with.

- With `ActivityStub`

  ```java
  GreetingActivities activities = Workflow.newActivityStub(GreetingActivities.class,
                  ActivityOptions.newBuilder()
                          // note that either StartToCloseTimeout or ScheduleToCloseTimeout are required when
                          // setting Activity options.
                          .setStartToCloseTimeout(Duration.ofSeconds(5))
                          .setTaskQueue("yourTaskQueue")
                          .build());
  ```

- With `WorkflowImplementationOptions`

  ```java
  WorkflowImplementationOptions options =
              WorkflowImplementationOptions.newBuilder()
                      .setActivityOptions(
                              ImmutableMap.of(
                                "EmailCustomerGreeting",
                                      ActivityOptions.newBuilder()
                                            // note that either StartToCloseTimeout or ScheduleToCloseTimeout are
                                            // required when setting Activity options.
                                            .setStartToCloseTimeout(Duration.ofSeconds(5))
                                            .setTaskQueue("yourTaskQueue")
                                            .build()))
                      .build();
  ```

See [Task Queue](/task-queue)

#### RetryOptions

To set a Retry Policy, known as the [Retry Options](/encyclopedia/retry-policies) in Java, use [`ActivityOptions.newBuilder.setRetryOptions()`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/activity/ActivityOptions.Builder.html).

- Type: `RetryOptions`
- Default: Server-defined Activity Retry policy.

- With `ActivityStub`

  ```java
  private final ActivityOptions options =
      ActivityOptions.newBuilder()
          // note that either StartToCloseTimeout or ScheduleToCloseTimeout are
          // required when setting Activity options.
          .setStartToCloseTimeout(Duration.ofSeconds(5))
          .setRetryOptions(
              RetryOptions.newBuilder()
                  .setInitialInterval(Duration.ofSeconds(1))
                  .setMaximumInterval(Duration.ofSeconds(10))
                  .build())
          .build();
  ```

- With `WorkflowImplementationOptions`

  ```java
  WorkflowImplementationOptions options =
          WorkflowImplementationOptions.newBuilder()
                 .setActivityOptions(
                      ImmutableMap.of(
                          "EmailCustomerGreeting",
                          ActivityOptions.newBuilder()
                                // note that either StartToCloseTimeout or ScheduleToCloseTimeout are
                                // required when setting Activity options.
                                .setStartToCloseTimeout(Duration.ofSeconds(5))
                                .setRetryOptions(
                                      RetryOptions.newBuilder()
                                          .setDoNotRetry(NullPointerException.class.getName())
                                          .build())
                                .build()))
                .build();
  ```

#### setCancellationType

- Type: `ActivityCancellationType`
- Default: `ActivityCancellationType.TRY_CANCEL`

- With `ActivityStub`

  ```java
  private final GreetingActivities activities =
    Workflow.newActivityStub(
        GreetingActivities.class,
        ActivityOptions.newBuilder()
            .setCancellationType(ActivityCancellationType.WAIT_CANCELLATION_COMPLETED)
            .build());
  ```

- With `WorkflowImplementationOptions`

  ```java
  WorkflowImplementationOptions options =
          WorkflowImplementationOptions.newBuilder()
                 .setActivityOptions(
                      ImmutableMap.of(
                          "EmailCustomerGreeting",
                          ActivityOptions.newBuilder()
                                .setCancellationType(ActivityCancellationType.WAIT_CANCELLATION_COMPLETED)
                                .build()))
                .build();
  ```

### Get the result of an Activity Execution {#activity-execution-result}

**How to get the result of an Activity Execution using the Java SDK.**

The call to spawn an [Activity Execution](/activity-execution) generates the [ScheduleActivityTask](/references/commands#scheduleactivitytask) Command and provides the Workflow with an Awaitable.
Workflow Executions can either block progress until the result is available through the Awaitable or continue progressing, making use of the result when it becomes available.

To get the results of an asynchronously invoked Activity method, use the `Promise` `get` method to block until the Activity method result is available.

Sometimes an Activity Execution lifecycle goes beyond a synchronous method invocation.
For example, a request can be put in a queue and later a reply comes and is picked up by a different Worker process.
The whole request-reply interaction can be modeled as a single Activity.

To indicate that an Activity should not be completed upon its method return, call `ActivityExecutionContext.doNotCompleteOnReturn()` from the original Activity thread.

Then later, when replies come, complete the Activity using the `ActivityCompletionClient`.
To correlate Activity invocation with completion, use either a `TaskToken` or Workflow and Activity Ids.

Following is an example of using `ActivityExecutionContext.doNotCompleteOnReturn()`:

```java
public class FileProcessingActivitiesImpl implements FileProcessingActivities {

  public String download(String bucketName, String remoteName, String localName) {

    ActivityExecutionContext ctx = Activity.getExecutionContext();

    // Used to correlate reply
    byte[] taskToken = ctx.getInfo().getTaskToken();

    asyncDownloadFileFromS3(taskToken, bucketName, remoteName, localDirectory + localName);
    ctx.doNotCompleteOnReturn();

    // Return value is ignored when doNotCompleteOnReturn was called.
    return "ignored";
  }
  ...
}
```

When the download is complete, the download service potentially can complete the Activity, or fail it from a different process, for example:

```java
  public <R> void completeActivity(byte[] taskToken, R result) {
    completionClient.complete(taskToken, result);
  }

  public void failActivity(byte[] taskToken, Exception failure) {
    completionClient.completeExceptionally(taskToken, failure);
  }
```

## Develop a Worker Program in Java {#run-a-dev-worker}

**How to develop a Worker Program using the Java SDK.**

The [Worker Process](/workers#worker-process) is where Workflow Functions and Activity Functions are executed.

- Each [Worker Entity](/workers#worker-entity) in the Worker Process must register the exact Workflow Types and Activity Types it may execute.
- Each Worker Entity must also associate itself with exactly one [Task Queue](/task-queue).
- Each Worker Entity polling the same Task Queue must be registered with the same Workflow Types and Activity Types.

A [Worker Entity](/workers#worker-entity) is the component within a Worker Process that listens to a specific Task Queue.

Although multiple Worker Entities can be in a single Worker Process, a single Worker Entity Worker Process may be perfectly sufficient.
For more information, see the [Worker tuning guide](/develop/worker-performance).

A Worker Entity contains a Workflow Worker and/or an Activity Worker, which makes progress on Workflow Executions and Activity Executions, respectively.

Use the `newWorker` method on an instance of a [`WorkerFactory`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/worker/WorkerFactory.html) to create a new Worker in Java.

A single Worker Entity can contain many Worker Objects.
Call the `start()` method on the instance of the `WorkerFactory` to start all the Workers created in this process.

```java
// ...

public class YourWorker {

  public static void main(String[] args) {

    WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
    WorkflowClient client = WorkflowClient.newInstance(service);
    WorkerFactory factory = WorkerFactory.newInstance(client);
    Worker yourWorker = factory.newWorker("your_task_queue");

    // Register Workflow
    // and/or register Activities

    factory.start();
  }
}
```

After creating the Worker entity, register all Workflow Types and all Activity Types that the Worker can execute.
A Worker can be registered with just Workflows, just Activities, or both.

**Operation guides:**

- [How to tune Workers](/develop/worker-performance)

### How to register types {#register-types}

**How to register Workflow and Activity Types with a Worker using the Java SDK.**

All Workers listening to the same Task Queue name must be registered to handle the exact same Workflows Types and Activity Types.

If a Worker polls a Task for a Workflow Type or Activity Type it does not know about, it fails that Task.
However, the failure of the Task does not cause the associated Workflow Execution to fail.

Use `worker.registerWorkflowImplementationTypes` to register Workflow Type and `worker.registerActivitiesImplementations` to register Activity implementation with Workers.

For Workflows, the Workflow Type is registered with a Worker.
A Workflow Type can be registered only once per Worker entity.
If you define multiple Workflow implementations of the same type, you get an exception at the time of registration.

For Activities, Activity implementation instances are registered with a Worker because they are stateless and thread-safe.
You can pass any number of dependencies in the Activity implementation constructor, such as the database connections, services, etc.

The following example shows how to register a Workflow and an Activity with a Worker.

```java
Worker worker = workerFactory.newWorker("your_task_queue");
...
// Register Workflow
worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class);
// Register Activity
worker.registerActivitiesImplementations(new GreetingActivitiesImpl());
```

When you register a single instance of an Activity, you can have multiple instances of Workflow Executions calling the same Activity.
Activity code must be thread-safe because the same instance of the Activity code is run for every Workflow Execution that calls it.

For `DynamicWorkflow`, only one Workflow implementation that extends `DynamicWorkflow` can be registered with a Worker.
The following example shows how to register the `DynamicWorkflow` and `DynamicActivity` implementation with a Worker.

```java
  public static void main(String[] arg) {

    WorkflowServiceStubs service = WorkflowServiceStubs.newInstance();
    WorkflowClient client = WorkflowClient.newInstance(service);
    WorkerFactory factory = WorkerFactory.newInstance(client);
    Worker worker = factory.newWorker(TASK_QUEUE);

    /* Register the Dynamic Workflow implementation with the Worker. Workflow implementations
    ** must be known to the Worker at runtime to dispatch Workflow Tasks.
    */
    worker.registerWorkflowImplementationTypes(DynamicGreetingWorkflowImpl.class);

    // Start all the Workers that are in this process.
    factory.start();

    /* Create the Workflow stub. Note that the Workflow Type is not explicitly registered with the Worker. */
    WorkflowOptions workflowOptions =
        WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId(WORKFLOW_ID).build();
    WorkflowStub workflow = client.newUntypedWorkflowStub("DynamicWF", workflowOptions);
    /**
     * Register Dynamic Activity implementation with the Worker. Since Activities are stateless
     * and thread-safe, we need to register a shared instance.
    */
    worker.registerActivitiesImplementations(new DynamicGreetingActivityImpl());

    /* Start Workflow Execution and immmediately send Signal. Pass in the Workflow args and Signal args. */
    workflow.signalWithStart("greetingSignal", new Object[] {"John"}, new Object[] {"Hello"});

    // Wait for the Workflow to finish getting the results.
    String result = workflow.getResult(String.class);

    System.out.println(result);

    System.exit(0);
  }
}
```

You can register multiple type-specific Workflow implementations alongside a single `DynamicWorkflow` implementation.
You can register only one Activity instance that implements `DynamicActivity` with a Worker.

---

## Debugging - Java SDK

In addition to writing unit and integration tests, debugging your Workflows is also a very valuable testing tool.
You can debug your Workflow code using a debugger provided by your favorite Java IDE.

Note that when debugging your Workflow code, the Temporal Java SDK includes deadlock detection which fails a Workflow Task in case the code blocks over a second without relinquishing execution control.
Because of this you can often encounter the `PotentialDeadlockException` Exception while stepping through Workflow code during debugging.

To alleviate this issue, you can set the `TEMPORAL_DEBUG` environment variable to true before debugging your Workflow code. Make sure to set `TEMPORAL_DEBUG` to true only during debugging.

## How to debug in a development environment {#debug-in-a-development-environment}

In addition to the normal development tools of logging and a debugger, you can also see what's happening in your Workflow by using the [Web UI](/web-ui) or [Temporal CLI](/cli).

## How to debug in a production environment {#debug-in-a-production-environment}

You can debug production Workflows using:

- [Web UI](/web-ui)
- [Temporal CLI](/cli)
- [Replay](/develop/java/testing-suite#replay)
- [Tracing](/develop/java/observability#tracing)
- [Logging](/develop/java/observability#logging)

You can debug and tune Worker performance with metrics and the [Worker performance guide](/develop/worker-performance).
For more information, see [Observability ▶️ Metrics](/develop/java/observability#metrics) for setting up SDK metrics.

Debug Server performance with [Cloud metrics](/cloud/metrics/) or [self-hosted Server metrics](/self-hosted-guide/production-checklist#scaling-and-metrics).

---

## Enriching the User Interface - Java SDK

Temporal supports adding context to Workflows and Events with metadata. 
This helps users identify and understand Workflows and their operations.

## Adding Summary and Details to Workflows

### Starting a Workflow

When starting a workflow, you can provide a static summary and details to help identify the Workflow in the UI:

```java

public class Main {
    public static void main(String[] args) {
        // Create service stubs and workflow client
        WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
        WorkflowClient workflowClient = WorkflowClient.newInstance(service);
        
        // Create workflow options with static summary and details
        WorkflowOptions options = WorkflowOptions.newBuilder()
                .setWorkflowId("your-workflow-id")
                .setTaskQueue("your-task-queue")
                .setStaticSummary("Order processing for customer #12345")
                .setStaticDetails("Processing premium order with expedited shipping")
                .build();
        
        // Create the workflow stub
        YourWorkflow workflow = workflowClient.newWorkflowStub(YourWorkflow.class, options);
        
        // Start the workflow
        String result = workflow.yourWorkflowMethod("workflow input");
    }
}
```

`setStaticSummary()` sets a single-line description that appears in the Workflow list view, limited to 200 bytes.
`setStaticDetails()` sets multi-line comprehensive information that appears in the Workflow details view, with a larger limit of 20K bytes.

The input format is standard Markdown excluding images, HTML, and scripts.

You can also use `WorkflowClient.start()` for async execution:

```java
// Start workflow asynchronously
WorkflowExecution execution = WorkflowClient.start(workflow::yourWorkflowMethod, "workflow input");
```

### Inside the Workflow

Within a Workflow, you can get and set the _current workflow details_. 
Unlike static summary/details set at Workflow start, this value can be updated throughout the life of the Workflow. 
Current Workflow details also takes Markdown format (excluding images, HTML, and scripts) and can span multiple lines.

```java

public class YourWorkflowImpl implements YourWorkflow {
    @Override
    public String yourWorkflowMethod(String input) {
        // Get the current details
        String currentDetails = Workflow.getCurrentDetails();
        Workflow.getLogger(YourWorkflowImpl.class).info("Current details: " + currentDetails);
        
        // Set/update the current details
        Workflow.setCurrentDetails("Updated workflow details with new status");
        
        return "Workflow completed";
    }
}
```

### Adding Summary to Activities and Timers

You can attach a `setSummary()` to Activities when starting them from within a Workflow:

```java

public class YourWorkflowImpl implements YourWorkflow {
    private final YourActivities activities = 
        Workflow.newActivityStub(YourActivities.class,
            ActivityOptions.newBuilder()
                .setStartToCloseTimeout(Duration.ofSeconds(10))
                .setSummary("Processing user data")
                .build());
    
    @Override
    public String yourWorkflowMethod(String input) {
        // Execute the activity with the summary
        String result = activities.yourActivity(input);
        return result;
    }
}
```

Similarly, you can attach a `setSummary()` to timers within a Workflow:

```java

public class YourWorkflowImpl implements YourWorkflow {
    @Override
    public String yourWorkflowMethod(String input) {
        // Create a timer with a summary
        Workflow.newTimer(Duration.ofMinutes(5), 
            TimerOptions.newBuilder()
                .setSummary("Waiting for payment confirmation")
                .build())
            .get(); // Wait for the timer to fire
        
        return "Timer completed";
    }
}
```

The input format for `setSummary()` is a string, and limited to 200 bytes.

## Viewing Summary and Details in the UI

Once you've added summaries and details to your Workflows, Activities, and Timers, you can view this enriched information in the Temporal Web UI. 
Navigate to your Workflow's details page to see the metadata displayed in two key locations:

### Workflow Overview Section

At the top of the workflow details page, you'll find the workflow-level metadata:

- **Summary & Details** - Displays the static summary and static details set when starting the workflow
- **Current Details** - Displays the dynamic details that can be updated during workflow execution

All Workflow details support standard Markdown formatting (excluding images, HTML, and scripts), allowing you to create rich, structured information displays.

### Event History

Individual events in the Workflow's Event History display their associated summaries when available.

Workflow, Activity and Timer summaries appear in purple text next to their corresponding events, providing immediate context without requiring you to expand the Event details. 
When you do expand an Event, the summary is also prominently displayed in the detailed view.

---

## Failure detection - Java SDK

This page shows how to do the following:

- [Set Workflow timeouts](#workflow-timeouts)
- [Set a Workflow Retry Policy](#workflow-retries)
- [Set Activity timeouts](#activity-timeouts)
- [Set a custom Activity Retry Policy](#activity-retries)
- [Heartbeat an Activity](#activity-heartbeats)
- [Set a Heartbeat Timeout](#heartbeat-timeout)

## Workflow timeouts {#workflow-timeouts}

**How to set Workflow timeouts using the Java SDK.**

Each Workflow timeout controls the maximum duration of a different aspect of a Workflow Execution.

Workflow timeouts are set when [starting the Workflow Execution](#workflow-timeouts).

Before we continue, we want to note that we generally do not recommend setting Workflow Timeouts, because Workflows are designed to be long-running and resilient.
Instead, setting a Timeout can limit its ability to handle unexpected delays or long-running processes.
If you need to perform an action inside your Workflow after a specific period of time, we recommend using a Timer.

- **[Workflow Execution Timeout](/encyclopedia/detecting-workflow-failures#workflow-execution-timeout)** - restricts the maximum amount of time that a single Workflow Execution can be executed.
- **[Workflow Run Timeout](/encyclopedia/detecting-workflow-failures#workflow-run-timeout):** restricts the maximum amount of time that a single Workflow Run can last.
- **[Workflow Task Timeout](/encyclopedia/detecting-workflow-failures#workflow-task-timeout):** restricts the maximum amount of time that a Worker can execute a Workflow Task.

Create an instance of [`WorkflowStub`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html) in the Client code and set your timeout.

Available timeouts are:

- [setWorkflowExecutionTimeout()](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowOptions.Builder.html#setWorkflowExecutionTimeout(java.time.Duration))
- [setWorkflowRunTimeout()](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowOptions.Builder.html#setWorkflowRunTimeout(java.time.Duration))
- [setWorkflowTaskTimeout()](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowOptions.Builder.html#setWorkflowTaskTimeout(java.time.Duration))

```java
//create Workflow stub for YourWorkflowInterface
YourWorkflowInterface workflow1 =
    WorkerGreet.greetclient.newWorkflowStub(
        GreetWorkflowInterface.class,
        WorkflowOptions.newBuilder()
                .setWorkflowId("YourWorkflow")
                .setTaskQueue(WorkerGreet.TASK_QUEUE)
                // Set Workflow Timeout duration
                .setWorkflowExecutionTimeout(Duration.ofSeconds(10))
                // .setWorkflowRunTimeout(Duration.ofSeconds(10))
                // .setWorkflowTaskTimeout(Duration.ofSeconds(10))
                .build());
```

### Workflow Retry Policy {#workflow-retries}

**How to set a Workflow Retry Policy in Java.**

A Retry Policy can work in cooperation with the timeouts to provide fine controls to optimize the execution experience.

Use a [Retry Policy](/encyclopedia/retry-policies) to retry a Workflow Execution in the event of a failure.

Workflow Executions do not retry by default, and Retry Policies should be used with Workflow Executions only in certain situations.

To set a Workflow Retry Options in the [`WorkflowStub`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html) instance use [`WorkflowOptions.Builder.setWorkflowRetryOptions`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowOptions.Builder.html).

- Type: `RetryOptions`
- Default: `Null` which means no retries will be attempted.

```java
//create Workflow stub for GreetWorkflowInterface
GreetWorkflowInterface workflow1 =
    WorkerGreet.greetclient.newWorkflowStub(
        GreetWorkflowInterface.class,
        WorkflowOptions.newBuilder()
                .setWorkflowId("GreetWF")
                .setTaskQueue(WorkerGreet.TASK_QUEUE)
                // Set Workflow Retry Options
                .setRetryOptions(RetryOptions.newBuilder()
                .build());
```

## Activity timeouts {#activity-timeouts}

**How to set Activity timeouts using the Java SDK.**

Each Activity timeout controls the maximum duration of a different aspect of an Activity Execution.

The following timeouts are available in the Activity Options.

- **[Schedule-To-Close Timeout](/encyclopedia/detecting-activity-failures#schedule-to-close-timeout):** is the maximum amount of time allowed for the overall [Activity Execution](/activity-execution).
- **[Start-To-Close Timeout](/encyclopedia/detecting-activity-failures#start-to-close-timeout):** is the maximum time allowed for a single [Activity Task Execution](/tasks#activity-task-execution).
- **[Schedule-To-Start Timeout](/encyclopedia/detecting-activity-failures#schedule-to-start-timeout):** is the maximum amount of time that is allowed from when an [Activity Task](/tasks#activity-task) is scheduled to when a [Worker](/workers#worker) starts that Activity Task.

An Activity Execution must have either the Start-To-Close or the Schedule-To-Close Timeout set.

Set your Activity Timeout from the [`ActivityOptions.Builder`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/activity/ActivityOptions.Builder.html) class.

Available timeouts are:

- ScheduleToCloseTimeout()
- ScheduleToStartTimeout()
- StartToCloseTimeout()

You can set Activity Options using an `ActivityStub` within a Workflow implementation, or per-Activity using `WorkflowImplementationOptions` within a Worker.

The following uses `ActivityStub`.

```java
GreetingActivities activities = Workflow.newActivityStub(GreetingActivities.class,
                ActivityOptions.newBuilder()
                        .setScheduleToCloseTimeout(Duration.ofSeconds(5))
                        // .setStartToCloseTimeout(Duration.ofSeconds(2)
                        // .setScheduletoCloseTimeout(Duration.ofSeconds(20))
                        .build());
```

The following uses `WorkflowImplementationOptions`.

```java
WorkflowImplementationOptions options =
            WorkflowImplementationOptions.newBuilder()
                    .setActivityOptions(
                            ImmutableMap.of(
                                    "GetCustomerGreeting",
                                    // Set Activity Execution timeout
                                    ActivityOptions.newBuilder()
                                        .setScheduleToCloseTimeout(Duration.ofSeconds(5))
                                        // .setStartToCloseTimeout(Duration.ofSeconds(2))
                                        // .setScheduleToStartTimeout(Duration.ofSeconds(5))
                                        .build()))
                    .build();
```

:::note

If you define options per-Activity Type options with `WorkflowImplementationOptions.setActivityOptions()`, setting them again specifically with `ActivityStub` in a Workflow will override this setting.

:::

### Custom Activity Retry Policy {#activity-retries}

**How to set a custom Activity Retry Policy in Java.**

A Retry Policy works in cooperation with the timeouts to provide fine controls to optimize the execution experience.

Activity Executions are automatically associated with a default [Retry Policy](/encyclopedia/retry-policies) if a custom one is not provided.

To set a Retry Policy, known as the [Retry Options](/encyclopedia/retry-policies) in Java, use [`ActivityOptions.newBuilder.setRetryOptions()`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/activity/ActivityOptions.Builder.html).

- Type: `RetryOptions`
- Default: Server-defined Activity Retry policy.

- With `ActivityStub`

  ```java
  private final ActivityOptions options =
      ActivityOptions.newBuilder()
          // note that either StartToCloseTimeout or ScheduleToCloseTimeout are
          // required when setting Activity options.
          .setStartToCloseTimeout(Duration.ofSeconds(5))
          .setRetryOptions(
              RetryOptions.newBuilder()
                  .setInitialInterval(Duration.ofSeconds(1))
                  .setMaximumInterval(Duration.ofSeconds(10))
                  .build())
          .build();
  ```

- With `WorkflowImplementationOptions`

  ```java
  WorkflowImplementationOptions options =
          WorkflowImplementationOptions.newBuilder()
                 .setActivityOptions(
                      ImmutableMap.of(
                          "EmailCustomerGreeting",
                          ActivityOptions.newBuilder()
                                // note that either StartToCloseTimeout or ScheduleToCloseTimeout are
                                // required when setting Activity options.
                                .setStartToCloseTimeout(Duration.ofSeconds(5))
                                .setRetryOptions(
                                      RetryOptions.newBuilder()
                                          .setDoNotRetry(NullPointerException.class.getName())
                                          .build())
                                .build()))
                .build();
  ```

## Activity next Retry delay {#activity-next-retry-delay}

**How to override the next Retry delay following an Activity failure using the Temporal Java SDK**

You may throw an [`ApplicationFailure`](/references/failures#application-failure) with the `NextRetryDelay` field set. This value will replace and override whatever the retry interval would be on the retry policy.

For example, if in an activity, you want to base the interval on the number of attempts, you might do:

```java
int attempt = Activity.getExecutionContext().getInfo().getAttempt();

throw ApplicationFailure.newFailureWithCauseAndDelay(
    "Something bad happened on attempt " + attempt,
    "my_failure_type",
    null,
    3 * Duration.ofSeconds(attempt));
```

## Heartbeat an Activity {#activity-heartbeats}

**How to Heartbeat an Activity using the Java SDK.**

An [Activity Heartbeat](/encyclopedia/detecting-activity-failures#activity-heartbeat) is a ping from the [Worker Process](/workers#worker-process) that is executing the Activity to the [Temporal Service](/temporal-service).
Each Heartbeat informs the Temporal Service that the [Activity Execution](/activity-execution) is making progress and the Worker has not crashed.
If the Temporal Service does not receive a Heartbeat within a [Heartbeat Timeout](/encyclopedia/detecting-activity-failures#heartbeat-timeout) time period, the Activity will be considered failed and another [Activity Task Execution](/tasks#activity-task-execution) may be scheduled according to the Retry Policy.

Heartbeats may not always be sent to the Temporal Service—they may be [throttled](/encyclopedia/detecting-activity-failures#throttling) by the Worker.

Activity Cancellations are delivered to Activities from the Temporal Service when they Heartbeat. Activities that don't Heartbeat can't receive a Cancellation.
Heartbeat throttling may lead to Cancellation getting delivered later than expected.

Heartbeats can contain a `details` field describing the Activity's current progress.
If an Activity gets retried, the Activity can access the `details` from the last Heartbeat that was sent to the Temporal Service.

To Heartbeat an Activity Execution in Java, use the `Activity.getExecutionContext().heartbeat()` Class method.

```java
public class YourActivityDefinitionImpl implements YourActivityDefinition {

  @Override
  public String yourActivityMethod(YourActivityMethodParam param) {
    // ...
    Activity.getExecutionContext().heartbeat(details);
    // ...
  }
  // ...
}
```

The method takes an optional argument, the `details` variable above that represents latest progress of the Activity Execution.
This method can take a variety of types such as an exception object, custom object, or string.

If the Activity Execution times out, the last Heartbeat `details` are included in the thrown `ActivityTimeoutException`, which can be caught by the calling Workflow.
The Workflow can then use the `details` information to pass to the next Activity invocation if needed.

In the case of Activity retries, the last Heartbeat's `details` are available and can be extracted from the last failed attempt by using `Activity.getExecutionContext().getHeartbeatDetails(Class<V> detailsClass)`

### Heartbeat Timeout {#heartbeat-timeout}

**How to set a Heartbeat Timeout using the Java SDK.**

A [Heartbeat Timeout](/encyclopedia/detecting-activity-failures#heartbeat-timeout) works in conjunction with [Activity Heartbeats](/encyclopedia/detecting-activity-failures#activity-heartbeat).

To set a [Heartbeat Timeout](/encyclopedia/detecting-activity-failures#heartbeat-timeout), use [`ActivityOptions.newBuilder.setHeartbeatTimeout`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/activity/ActivityOptions.Builder.html).

- Type: `Duration`
- Default: None

You can set Activity Options using an `ActivityStub` within a Workflow implementation, or per-Activity using `WorkflowImplementationOptions` within a Worker.
Note that if you define options per-Activity Type options with `WorkflowImplementationOptions.setActivityOptions()`, setting them again specifically with `ActivityStub` in a Workflow will override this setting.

- With `ActivityStub`

  ```java
  private final GreetingActivities activities =
      Workflow.newActivityStub(
          GreetingActivities.class,
          ActivityOptions.newBuilder()
              // note that either StartToCloseTimeout or ScheduleToCloseTimeout are
              // required when setting Activity options.
              .setStartToCloseTimeout(Duration.ofSeconds(5))
              .setHeartbeatTimeout(Duration.ofSeconds(2))
              .build());
  ```

- With `WorkflowImplementationOptions`

  ```java
  WorkflowImplementationOptions options =
              WorkflowImplementationOptions.newBuilder()
                      .setActivityOptions(
                              ImmutableMap.of(
                                "EmailCustomerGreeting",
                                      ActivityOptions.newBuilder()
                                          // note that either StartToCloseTimeout or ScheduleToCloseTimeout are
                                          // required when setting Activity options.
                                            .setStartToCloseTimeout(Duration.ofSeconds(5))
                                            .setHeartbeatTimeout(Duration.ofSeconds(2))
                                            .build()))
                      .build();
  ```

---

## Java SDK developer guide

![Java SDK Banner](/img/assets/banner-java-temporal.png)

:::info JAVA SPECIFIC RESOURCES
Build Temporal Applications with the Java SDK.

**Temporal Java Technical Resources:**

- [Java SDK Quickstart - Setup Guide](https://docs.temporal.io/develop/java/set-up-your-local-java)
- [Java API Documentation](https://javadoc.io/doc/io.temporal/temporal-sdk)
- [Java SDK Code Samples](https://github.com/temporalio/samples-java)
- [Java SDK GitHub](https://github.com/temporalio/sdk-java)
- [Temporal 101 in Java Free Course](https://learn.temporal.io/courses/temporal_101/java/)

**Get Connected with the Temporal Java Community:**

- [Temporal Java Community Slack](https://temporalio.slack.com/archives/CTT84KXK9)
- [Java SDK Forum](https://community.temporal.io/tag/java-sdk)
  :::

## [Core application](/develop/java/core-application)

Use the essential components of a Temporal Application (Workflows, Activities, and Workers) to build and run a Temporal application.

- [How to develop a Workflow Definition in Java](/develop/java/core-application#develop-workflows)
- [How to develop a basic Activity](/develop/java/core-application#develop-activities)
- [How to start an Activity Execution](/develop/java/core-application#activity-execution)
- [How to develop a Worker Program in Java](/develop/java/core-application#run-a-dev-worker)

## [Temporal Client](/develop/java/temporal-client)

Connect to a Temporal Service and start a Workflow Execution.

- [Connect to a development Temporal Service](/develop/java/temporal-client#connect-to-development-service)
- [Connect to Temporal Cloud](/develop/java/temporal-client#connect-to-temporal-cloud)
- [Start a Workflow Execution](/develop/java/temporal-client#start-workflow-execution)

## [Testing](/develop/java/testing-suite)

Set up the testing suite and test Workflows and Activities.

- [Test frameworks](/develop/java/testing-suite#test-frameworks)
- [Test Activities](/develop/java/testing-suite#test-activities)
- [Testing Workflows](/develop/java/testing-suite#test-workflows)
- [How to Replay a Workflow Execution](/develop/java/testing-suite#replay)

## [Failure detection](/develop/java/failure-detection)

Explore how your application can detect failures using timeouts and automatically attempt to mitigate them with retries.

- [Workflow timeouts](/develop/java/failure-detection#workflow-timeouts)
- [How to set Activity timeouts](/develop/java/failure-detection#activity-timeouts)
- [How to Heartbeat an Activity](/develop/java/failure-detection#activity-heartbeats)

## [Workflow message passing](/develop/java/message-passing)

Send messages to and read the state of Workflow Executions.

- [How to develop with Signals](/develop/java/message-passing#signals)
- [How to develop with Queries](/develop/java/message-passing#queries)
- [What is a Dynamic Handler?](/develop/java/message-passing#dynamic-handler)
- [How to develop with Updates](/develop/java/message-passing#updates)

## [Asynchronous Activity completion](/develop/java/asynchronous-activity-completion)

Complete Activities asynchronously.

- [How to asynchronously complete an Activity](/develop/java/asynchronous-activity-completion)

## [Versioning](/develop/java/versioning)

Change Workflow Definitions without causing non-deterministic behavior in running Workflows.

- [Temporal Java SDK Versioning APIs](/develop/java/versioning#patching)

## [Observability](/develop/java/observability)

Configure and use the Temporal Observability APIs.

- [How to emit metrics](/develop/java/observability#metrics)
- [How to setup Tracing](/develop/java/observability#tracing)
- [How to log from a Workflow](/develop/java/observability#logging)
- [How to use Visibility APIs](/develop/java/observability#visibility)

## [Debugging](/develop/java/debugging)

Explore various ways to debug your application.

- [How to debug in a development environment](/develop/java/debugging#debug-in-a-development-environment)
- [How to debug in a production environment](/develop/java/debugging#debug-in-a-production-environment)

## [Schedules](/develop/java/schedules)

Run Workflows on a schedule and delay the start of a Workflow.

- [How to Schedule a Workflow](/develop/java/schedules#schedule-a-workflow)
- [How to set a Cron Schedule in Java](/develop/java/schedules#cron-schedule)

## [Data encryption](/develop/java/converters-and-encryption)

Use compression, encryption, and other data handling by implementing custom converters and codecs.

- [How to use a custom Payload Codec in Java](/develop/java/converters-and-encryption#custom-payload-codec)
- [How to use custom Payload conversion](/develop/java/converters-and-encryption#custom-payload-conversion)

## Temporal Nexus

The [Temporal Nexus](/develop/java/nexus) feature guide shows how to use Temporal Nexus to connect Durable Executions within and across Namespaces using a Nexus Endpoint, a Nexus Service contract, and Nexus Operations.

- [Create a Nexus Endpoint to route requests from caller to handler](/develop/java/nexus#create-nexus-endpoint)
- [Define the Nexus Service contract](/develop/java/nexus#define-nexus-service-contract)
- [Develop a Nexus Service and Operation handlers](/develop/java/nexus#develop-nexus-service-operation-handlers)
- [Develop a caller Workflow that uses a Nexus Service](/develop/java/nexus#develop-caller-workflow-nexus-service)
- [Make Nexus calls across Namespaces with a development Server](/develop/java/nexus#nexus-calls-across-namespaces-dev-server)
- [Make Nexus calls across Namespaces in Temporal Cloud](/develop/java/nexus#nexus-calls-across-namespaces-temporal-cloud)

## [Interrupt a Workflow feature guide](/develop/java/cancellation)

Interrupt a Workflow Execution with a Cancel or Terminate action.

- [Cancel a Workflow](/develop/java/cancellation#cancellation)
- [Terminate a Workflow](/develop/java/cancellation#termination)
- [Reset a Workflow](/develop/java/cancellation#reset): Resume a Workflow Execution from an earlier point in its Event History.
- [Cancel an Activity from a Workflow](/develop/java/cancellation#cancel-activity)

## [Child Workflows](/develop/java/child-workflows)

Explore how to spawn a Child Workflow Execution and handle Child Workflow Events.

- [Start a Child Workflow Execution](/develop/java/child-workflows#start-child-workflow)
- [Set a Parent Close Policy](/develop/java/child-workflows#parent-close-policy)

## [Continue-As-New](/develop/java/continue-as-new)

Continue the Workflow Execution with a new Workflow Execution using the same Workflow ID.

- [Continue a Workflow as New](/develop/java/continue-as-new)

## [Durable Timers](/develop/java/timers)

Use Timers to make a Workflow Execution pause or "sleep" for seconds, minutes, days, months, or years.

- [What is a Timer?](/develop/java/timers#timers)

## [Side Effects](/develop/java/side-effects)

Use Side Effects in Workflows.

- [Side Effects](/develop/java/side-effects#side-effects)

## [Enriching the User Interface](/develop/java/enriching-ui)

Add descriptive information to workflows and events for better visibility and context in the UI.

- [Adding Summary and Details to Workflows](/develop/java/enriching-ui#adding-summary-and-details-to-workflows)

## [Manage Namespaces](/develop/java/namespaces)

Create and manage Namespaces.

- [Create a Namespace](/develop/java/namespaces#register-namespace)
- [Manage Namespaces](/develop/java/namespaces#manage-namespaces)

## [Spring Boot](/develop/java/spring-boot-integration)

Use Temporal in your Spring Boot application.

- [Spring Boot](/develop/java/spring-boot-integration#setup-dependency)

---

## Workflow message passing - Java SDK

A Workflow can act like a stateful web service that receives messages: Queries, Signals, and Updates.
The Workflow implementation defines these endpoints via handler methods that can react to incoming messages and return values.
Temporal Clients use messages to read Workflow state and control execution.
See [Workflow message passing](/encyclopedia/workflow-message-passing) for a general overview of this topic.
This page introduces these features for the Temporal Java SDK.

## Write message handlers {#writing-message-handlers}

Follow these guidelines when writing your message handlers:

- Message handlers are defined as methods on the Workflow class, using one of the three annotations: [`@QueryMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/QueryMethod.html), [`@SignalMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/SignalMethod.html), and [`@UpdateMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/UpdateMethod.html).
- The parameters and return values of handlers and the main Workflow function must be [serializable](/dataconversion).
- Prefer a single class with multiple fields over using multiple input parameters.
  A class allows you to add fields without changing the calling signature.

### Query handlers {#queries}

A [Query](/sending-messages#sending-queries) is a synchronous operation that retrieves state from a Workflow Execution:

```java
public class MessagePassingIntro {

    public enum Language {
        CHINESE,
        ENGLISH,
        FRENCH,
        SPANISH,
        PORTUGUESE,
    }

    public static class GetLanguagesInput {
        public boolean includeUnsupported;

        public GetLanguagesInput() {
            this.includeUnsupported = false;
        }

        public GetLanguagesInput(boolean includeUnsupported) {
            this.includeUnsupported = includeUnsupported;
        }
    }

    @WorkflowInterface
    public interface GreetingWorkflow {
        ...
        // 👉 Use the @QueryMethod annotation to define a Query handler in the
        // Workflow interface.
        @QueryMethod
        List<Language> getLanguages(GetLanguagesInput input);
    }

    public static class GreetingWorkflowImpl implements GreetingWorkflow {
        ...
        @Override
        public List<Language> getLanguages(GetLanguagesInput input) {
            // 👉 The Query handler returns a value: it must not mutate the Workflow state
            // or perform blocking operations.
            if (input.includeUnsupported) {
                return Arrays.asList(Language.values());
            } else {
                return new ArrayList(greetings.keySet());
            }
        }
    }

}
```

- A Query handler must not modify Workflow state.
- You can't perform blocking operations such as executing an Activity in a Query handler.
- The Query annotation accepts an argument (`name`) as described in the API reference docs for [`@QueryMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/QueryMethod.html).

### Signal handlers {#signals}

A [Signal](/sending-messages#sending-signals) is an asynchronous message sent to a running Workflow Execution to change its state and control its flow:

```java
public class MessagePassingIntro {

    public static class ApproveInput {
        private String name;

        public ApproveInput() {}

        public ApproveInput(String name) {
            this.name = name;
        }
    }

    @WorkflowInterface
    public interface GreetingWorkflow {
        ...
        // 👉 Use the @SignalMethod annotation to define a Signal handler in the
        // Workflow interface.
        @SignalMethod
        void approve(ApproveInput input);
    }

    public static class GreetingWorkflowImpl implements GreetingWorkflow {
        ...
        private Boolean approvedForRelease;
        private String approverName;

        @Override
        public void approve(ApproveInput input) {
            // 👉 The Signal handler mutates the Workflow state but cannot return a value.
            this.approvedForRelease = true;
            this.approverName = input.name;
        }
    }
}
```

- The handler should not return a value.
  The response is sent immediately from the server, without waiting for the Workflow to process the Signal.

- The Signal annotation accepts arguments (`name`, and `unfinished_policy`) as described in the API reference docs for [`@SignalMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/SignalMethod.html).

- Signal (and Update) handlers can be blocking.
  This allows you to use Activities, Child Workflows, durable [`Workflow.sleep`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#sleep(java.time.Duration)) Timers, [`Workflow.await`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#await(java.time.Duration,java.util.function.Supplier)), and more.
  See [Blocking handlers](#blocking-handlers) and [Workflow message passing](/encyclopedia/workflow-message-passing) for guidelines on safely using blocking Signal and Update handlers.

### Update handlers and validators {#updates}

An [Update](/sending-messages#sending-updates) is a trackable synchronous request sent to a running Workflow Execution.
It can change the Workflow state, control its flow, and return a result.
The sender must wait until the Worker accepts or rejects the Update.
The sender may wait further to receive a returned value or an exception if something goes wrong:

```java
public class MessagePassingIntro {
    @WorkflowInterface
    public interface GreetingWorkflow {
        ...
        // 👉 Use the @UpdateMethod annotation to define an Update handler in the
        // Workflow interface.
        @UpdateMethod
        Language setLanguage(Language language);

        // 👉 Update validators are optional
        @UpdateValidatorMethod(updateName = "setLanguage")
        void setLanguageValidator(Language language);
    }

    public static class GreetingWorkflowImpl implements GreetingWorkflow {
        ...
        @Override
        public Language setLanguage(Language language) {
            // 👉 The Update handler can mutate the Workflow state and return a value.
            Language previousLanguage = this.language;
            this.language = language;
            return previousLanguage;
        }

        @Override
        public void setLanguageValidator(Language language) {
            // 👉 The Update validator performs validation but cannot mutate the Workflow state.
            if (!greetings.containsKey(language)) {
                throw new IllegalArgumentException("Unsupported language: " + language);
            }
        }
    }
}
```

- The Update annotation accepts arguments (`name`, and `unfinished_policy`) as described in the API reference docs for [`@UpdateMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/UpdateMethod.html).

- About validators:
  - Use validators to reject an Update before it is written to History.
    Validators are always optional.
    If you don't need to reject Updates, you can skip them.
  - Define an Update validator with the `@UpdateValidatorMethod` annotation.
    Use the `updateName` argument when declaring the validator to connect it to its Update.
    The validator must return `void` and accept the same argument types as the handler.

- Accepting and rejecting Updates with validators:
  - To reject an Update, throw an exception of any type in the validator.
  - Without a validator, Updates are always accepted.
- Validators and Event History:
  - The `WorkflowExecutionUpdateAccepted` event is written into the History whether the acceptance was automatic or programmatic.
  - When a Validator throws an error, the Update is rejected, the Update is not run, and `WorkflowExecutionUpdateAccepted` _won't_ be added to the Event History.
    The caller receives an "Update failed" error.

- Use [`getCurrentUpdateInfo`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/internal/sync/WorkflowInternal.html#getCurrentUpdateInfo()) to obtain information about the current Update. This includes the Update ID, which can be useful for deduplication when using Continue-As-New: see [Ensuring your messages are processed exactly once](https://docs.temporal.io/handling-messages#exactly-once-message-processing).

- Signal (and Update) handlers can be blocking, letting them use Activities, Child Workflows, durable [`Workflow.sleep`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#sleep(java.time.Duration)) Timers, [`Workflow.await`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#await(java.time.Duration,java.util.function.Supplier)) conditions, and more.
  See [Blocking handlers](#blocking-handlers) and [Workflow message passing](/encyclopedia/workflow-message-passing) for safe usage guidelines.

## Send messages {#send-messages}

To send Queries, Signals, or Updates you call methods on a `WorkflowInterface`, often called the "WorkflowStub."

Use [newWorkflowStub](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowClient.html#newWorkflowStub(java.lang.Class,io.temporal.client.WorkflowOptions)) to obtain the WorkflowStub.

For example:

```java
WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();

WorkflowClient client = WorkflowClient.newInstance(service);

WorkflowOptions workflowOptions =
    WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).setWorkflowId(WORKFLOW_ID).build();

// Create the workflow client stub. It is used to start the workflow execution.
GreetingWorkflow workflow = client.newWorkflowStub(GreetingWorkflow.class, workflowOptions);

// Start workflow asynchronously and call its getGreeting workflow method
WorkflowClient.start(workflow::getGreetings);
```

To check the argument types required when sending messages -- and the return type for Queries and Updates -- refer to the corresponding handler method in the Workflow Definition.

:::warning Using Continue-as-New and Updates

- Temporal _does not_ support Continue-as-New functionality within Update handlers.
- Complete all handlers _before_ using Continue-as-New.
- Use Continue-as-New from your main Workflow Definition method, just as you would complete or fail a Workflow Execution.

:::

### Send a Query {#send-query}

Call a Query method defined within a Workflow from a `WorkflowStub` created in Client code to send a Query to a Workflow Execution:

```java
List<Language> languages = workflow.getLanguages(new GetLanguagesInput(false));
System.out.println("Supported languages: " + languages);
```

- Sending a Query doesn’t add events to a Workflow's Event History.

- You can send Queries to closed Workflow Executions within a Namespace's Workflow retention period.
  This includes Workflows that have completed, failed, or timed out.
  Querying terminated Workflows is not safe and, therefore, not supported.

- A Worker must be online and polling the Task Queue to process a Query.

### Send a Signal {#send-signal}

You can send a Signal to a Workflow Execution from a Temporal Client or from another Workflow Execution.
However, you can only send Signals to Workflow Executions that haven’t closed.

#### Send a Signal from a Client {#send-signal-from-client}

To send a Signal from Client code, call a Signal method on the WorkflowStub:

```java
workflow.approve(new ApproveInput("Me"));
```

- The call returns when the server accepts the Signal; it does _not_ wait for the Signal to be delivered to the Workflow Execution.

- The [WorkflowExecutionSignaled](/references/events#workflowexecutionsignaled) Event appears in the Workflow's Event History.

#### Send a Signal from a Workflow {#send-signal-from-workflow}

A Workflow can send a Signal to another Workflow, known as an _External Signal_.
Use [`Workflow.newExternalWorkflowStub`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#newExternalWorkflowStub(java.lang.Class,io.temporal.api.common.v1.WorkflowExecution)) in your _current_ Workflow to create an `ExternalWorkflowStub` for the other Workflow.
Call Signal methods on the external stub to Signal the other Workflow:

```java
OtherWorkflow other = Workflow.newExternalWorkflowStub(OtherWorkflow.class, otherWorkflowID);
other.mySignalMethod();
```

When an External Signal is sent:

- A [SignalExternalWorkflowExecutionInitiated](/references/events#signalexternalworkflowexecutioninitiated) Event appears in the sender's Event History.
- A [WorkflowExecutionSignaled](/references/events#workflowexecutionsignaled) Event appears in the recipient's Event History.

#### Signal-With-Start {#signal-with-start}

Signal-With-Start allows a Client to send a Signal to a Workflow Execution, starting the Execution if it is not already running.
If there's a Workflow running with the given Workflow Id, it will be signaled.
If there isn't, a new Workflow will be started and immediately signaled.
To use Signal-With-Start, call `signalWithStart` and pass the name of your Signal with its arguments:

```java
public static void signalWithStart() {
    // WorkflowStub is a client-side stub to a single Workflow instance
    WorkflowStub untypedWorkflowStub = client.newUntypedWorkflowStub("GreetingWorkflow",
    WorkflowOptions.newBuilder()
            .setWorkflowId(workflowId)
            .setTaskQueue(taskQueue)
            .build());

    untypedWorkflowStub.signalWithStart("setCustomer", new Object[] {customer2}, new Object[] {customer1});

    String greeting = untypedWorkflowStub.getResult(String.class);
}
```

Here's the `WorkflowInterface` for the previous example.
When using Signal-With-Start, the Signal handler (`setCustomer`) will be executed before the Workflow method (`greet`).

```java
@WorkflowInterface
public interface GreetingWorkflow {
    @WorkflowMethod
    String greet(Customer customer);

    @SignalMethod
    void setCustomer(Customer customer);

    @QueryMethod
    Customer getCustomer();
}
```

### Send an Update {#send-update-from-client}

An Update is a synchronous, blocking call that can change Workflow state, control its flow, and return a result.

A Client sending an Update must wait until the Server delivers the Update to a Worker.
Workers must be available and responsive.
If you need a response as soon as the Server receives the request, use a Signal instead.
Also note that you can't send Updates to other Workflow Executions.

- `WorkflowExecutionUpdateAccepted` is added to the Event History when the Worker confirms that the Update passed validation.
- `WorkflowExecutionUpdateCompleted` is added to the Event History when the Worker confirms that the Update has finished.

To send an Update to a Workflow Execution, you can:

- Call the Update method on a WorkflowStub in Client code and wait for the Update to complete.
  This code fetches an Update result:

  ```java
  Language previousLanguage = workflow.setLanguage(Language.CHINESE);
  ```

- Send [`startUpdate`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#startUpdate(io.temporal.client.UpdateOptions,java.lang.Object...)) to receive an [`WorkflowUpdateHandle`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowUpdateHandle.html) as soon as the Update is accepted or rejected.

  - Use this `WorkflowUpdateHandle` later to fetch your results.
  - Blocking Update handlers normally perform long-running asynchronous operations.
  - `startUpdate` only waits until the Worker has accepted or rejected the Update, not until all asynchronous operations are complete.

  For example:

  ```java
  WorkflowUpdateHandle<Language> handle =
      WorkflowStub.fromTyped(workflow)
          .startUpdate(
              "setLanguage", WorkflowUpdateStage.ACCEPTED, Language.class, Language.ENGLISH);
  previousLanguage = handle.getResultAsync().get();
  ```

  For more details, see the "Blocking handlers" section.

To obtain an Update handle, you can:

- Use [`startUpdate`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#startUpdate(io.temporal.client.UpdateOptions,java.lang.Object...)) to start an Update and return the handle, as shown in the preceding example.
- Use [`getUpdateHandle`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#getUpdateHandle(java.lang.String,java.lang.Class)) to fetch a handle for an in-progress Update using the Update ID and Workflow ID.

You can use the `WorkflowUpdateHandle` to obtain information about the update:

- `getExecution()`: Returns the Workflow Execution that this Update was sent to.
- `getId()`: Returns the Update's unique ID, which can be useful for deduplication when using Continue-As-New: see [Ensuring your messages are processed exactly once](/handling-messages#exactly-once-message-processing).
- `getResultAsync()`: Returns a `CompletableFuture` which can be used to wait for the Update to complete.

#### Update-With-Start {#update-with-start}

:::tip

For open source server users, Temporal Server version [Temporal Server version 1.28](https://github.com/temporalio/temporal/releases/tag/v1.28.0) is recommended.

:::

[Update-with-Start](/sending-messages#update-with-start) lets you
[send an Update](/develop/java/message-passing#send-update-from-client) that checks whether an already-running Workflow with that ID exists:

- If the Workflow exists, the Update is processed.
- If the Workflow does not exist, a new Workflow Execution is started with the given ID, and the Update is processed before the main Workflow method starts to execute.

Use the [`startUpdateWithStart`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowClient.html#startUpdateWithStart(io.temporal.workflow.Functions.Func,io.temporal.client.UpdateOptions,io.temporal.client.WithStartWorkflowOperation)) WorkflowClient API.
It returns once the requested Update wait stage has been reached; or when the request times out.
Use the [`WorkflowUpdateHandle`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowUpdateHandle.html) to retrieve a result from the Update.

You will need to provide:

- WorkflowStub created from [`WorkflowOptions`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowOptions.html).
  The `WorkflowOptions` require [Workflow Id Conflict Policy](/workflow-execution/workflowid-runid#workflow-id-conflict-policy) to be specified.
  Choose "Use Existing" and use an idempotent Update handler to ensure your code can be executed again in case of a Client failure.
  Not all `WorkflowOptions` are allowed.
  For example, specifying a Cron Schedule will result in an error.

- [`UpdateOptions`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/UpdateOptions.html).
  Same as for [Update Workflow](/develop/java/message-passing#send-update-from-client), the update wait stage must be specified.
  For Update-with-Start, the Workflow Id is optional.
  When specified, the Id must match the one used in `WorkflowOptions`.
  Since a running Workflow Execution may not already exist, you can't set a Run Id.

- [`WithStartWorkflowOperation`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WithStartWorkflowOperation.html).
  Specify the workflow method.
  Note that a `WithStartWorkflowOperation` can only be used once.
  Re-using a previously used operation returns an error from `startUpdateWithStart`.

For example:

```java
WorkflowUpdateHandle<Language> handle =
    WorkflowClient.startUpdateWithStart(
        workflow::setLanguage,
        Language.ENGLISH,
        UpdateOptions.<Language>newBuilder().setWaitForStage(WorkflowUpdateStage.ACCEPTED).build(),
        new WithStartWorkflowOperation<>(workflow::getGreetings));

Language previousLanguage = handle.getResultAsync().get();
```

To obtain the update result directly, use the [`executeUpdateWithStart`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowClient.html#executeUpdateWithStart(io.temporal.workflow.Functions.Func,io.temporal.client.UpdateOptions,io.temporal.client.WithStartWorkflowOperation)) WorkflowClient API.
It returns once the update result is available; or when the API call times out.
The update wait stage on the `UpdateOptions` is optional.
When specified, it must be `WorkflowUpdateStage.COMPLETED`.

For example:

```java
Language previousLanguage =
    WorkflowClient.executeUpdateWithStart(
        workflow::setLanguage,
        Language.ENGLISH,
        UpdateOptions.<Language>newBuilder().build(),
        new WithStartWorkflowOperation<>(workflow::getGreetings));
```

For more examples, see the [Java sample for early-return pattern](https://github.com/temporalio/samples-java/tree/main/core/src/main/java/io/temporal/samples/earlyreturn).

:::info NON-TYPE SAFE API CALLS

In real-world development, sometimes you may be unable to import Workflow Definition method signatures.
When you don't have access to the Workflow Definition or it isn't written in Java, you can use these non-type safe APIs to obtain an untyped WorkflowStub:

- [`WorkflowClient.newUntypedWorkflowStub`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowClient.html#newUntypedWorkflowStub(java.lang.String,io.temporal.client.WorkflowOptions))
- [`Workflow.newUntypedExternalWorkflowStub`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#newUntypedExternalWorkflowStub(java.lang.String)).

Pass method names instead of method objects to:

- [`WorkflowStub.query`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#query(java.lang.String,java.lang.Class,java.lang.Object...))
- [`WorkflowStub.signal`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#signal(java.lang.String,java.lang.Object...))
- [`WorkflowStub.update`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#update(java.lang.String,java.lang.Class,java.lang.Object...))
- [`WorkflowStub.startUpdateWithStart`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#startUpdateWithStart(io.temporal.client.UpdateOptions,java.lang.Object%5B%5D,java.lang.Object%5B%5D))
- [`WorkflowStub.executeUpdateWithStart`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html#executeUpdateWithStart(io.temporal.client.UpdateOptions,java.lang.Object%5B%5D,java.lang.Object%5B%5D))

:::

## Message handler patterns {#message-handler-patterns}

This section covers common write operations, such as Signal and Update handlers.
It doesn't apply to pure read operations, like Queries or Update Validators.

:::tip

For additional information, see [Inject work into the main Workflow](/handling-messages#injecting-work-into-main-workflow), and [Ensuring your messages are processed exactly once](/handling-messages#exactly-once-message-processing).

:::

### Do blocking operations in handlers {#blocking-handlers}

Signal and Update handlers can block.
This allows you to use [`Workflow.await`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#await(java.time.Duration,java.util.function.Supplier)), Activities, Child Workflows, [`Workflow.sleep`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#sleep(java.time.Duration)) Timers, etc.
This expands the possibilities for what can be done by a handler but it also means that handler executions and your main Workflow method are all running concurrently, with switching occurring between them at await calls.

It's essential to understand the things that could go wrong in order to use blocking handlers safely.
See [Workflow message passing](/encyclopedia/workflow-message-passing) for guidance on safe usage of blocking Signal and Update handlers, and the [Controlling handler concurrency](#control-handler-concurrency) and [Waiting for message handlers to finish](#wait-for-message-handlers) sections below.

The following code modifies the Update handler from earlier on in this page.
The Update handler now makes a blocking call to execute an Activity:

```java
public static class GreetingWorkflowImpl implements GreetingWorkflow {
    ...
    @Override
    public Language setLanguage(Language language) {
        if (!greetings.containsKey(language)) {
            String greeting = activity.greetingService(language);
            if (greeting == null) {
                // 👉 An update validator cannot be blocking, so cannot be used to check that the remote
                // greetingService supports the requested language. Throwing an ApplicationFailure
                // will fail the Update, but the WorkflowExecutionUpdateAccepted event will still be
                // added to history.
                throw ApplicationFailure.newFailure("Greeting service does not support: " + language, "GreetingFailure")
            }
            greetings.put(language, greeting);
        }
        Language previousLanguage = this.language;
        this.language = language;
        return previousLanguage;
    }
}
```

Although a Signal handler can also make blocking calls like this, using an Update handler allows the Client to receive a result or error once the Activity completes.
This lets your Client track the progress of asynchronous work performed by the Update's Activities, Child Workflows, etc.

### Add blocking wait conditions {#block-with-wait}

Sometimes, blocking Signal or Update handlers need to meet certain conditions before they should continue.
You can use [`Workflow.await`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#await(java.time.Duration,java.util.function.Supplier)) to prevent the code from proceeding until a condition is true.
You specify the condition by passing a function that returns `true` or `false`.
This is an important feature that helps you control your handler logic.

Here are two important use cases for `Workflow.await`:

- Waiting in a handler until it is appropriate to continue.
- Waiting in the main Workflow until all active handlers have finished.

#### Wait for conditions in handlers {#wait-in-handlers}

It's common to use `Workflow.await` in a handler.
For example, suppose your Workflow class has a `updateReadyToExecute` method that indicates whether your Update handler should be allowed to start executing.
You can use `workflow.wait_condition` in the handler to make the handler pause until the condition is met:

```java
@Override
public String setLanguage(UpdateInput input) {
    Workflow.await(() -> this.updateReadyToExecute(input));
    ...
}
```

Remember: handlers can execute before the main Workflow method starts.

You can also use `Workflow.await` anywhere else in the handler to wait for a specific condition to become true.
This allows you to write handlers that pause at multiple points, each time waiting for a required condition to become true.

#### Ensure your handlers finish before the Workflow completes {#wait-for-message-handlers}

`Workflow.await` can ensure your handler completes before a Workflow finishes.
When your Workflow uses blocking Signal or Update handlers, your main Workflow method can return or Continue-as-New while a handler is still waiting on an async task, such as an Activity.
The Workflow completing may interrupt the handler before it finishes crucial work and cause Client errors when trying to retrieve Update results.
Use `Workflow.await` to wait for [`Workflow.isEveryHandlerFinished`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#isEveryHandlerFinished()) to return `true` to address this problem and allow your Workflow to end smoothly:

```java
public class MyWorkflowImpl implements MyWorkflow {
    ...
    @Override
    public String run() {
        ...
        Workflow.await(() -> Workflow.isEveryHandlerFinished());
        return "workflow-result";
    }
}
```

By default, your Worker will log a warning when you allow a Workflow Execution to finish with unfinished handler executions.
You can silence these warnings on a per-handler basis by passing the `unfinishedPolicy` argument to the [`@SignalMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/SignalMethod.html) / [`@UpdateMethod`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/UpdateMethod.html) annotation:

```java
@WorkflowInterface
public interface MyWorkflow {
    ...
    @UpdateMethod(unfinishedPolicy = HandlerUnfinishedPolicy.ABANDON)
    void myUpdate();
}
```

See [Finishing handlers before the Workflow completes](/handling-messages#finishing-message-handlers) for more information.

### Use `@WorkflowInit` to operate on Workflow input before any handler executes

Normally, your Workflows constructor won't have any parameters.
However, if you use the `@WorkflowInit` annotation on your constructor, you can give it the same [Workflow parameters](/develop/java/core-application#workflow-parameters) as your `@WorkflowMethod`.
The SDK will then ensure that your constructor receives the Workflow input arguments that the [Client sent](/develop/java/temporal-client#start-workflow-execution).
The Workflow input arguments are also passed to your `@WorkflowMethod` method -- that always happens, whether or not you use the `@WorkflowInit` annotation.
This is useful if you have message handlers that need access to Workflow input: see [Initializing the Workflow first](/handling-messages#workflow-initializers).

:::caution

Do not make blocking calls from within your `@WorkflowInit` method. This could result in your Workflow being incompletely initialized at the start, meaning, for example, that Signal, Query, and Update handler registration would be delayed.

:::

Here's an example.
Notice that the constructor and `getGreeting` must have the same parameters:

```java
public class GreetingExample {
    @WorkflowInterface
    public interface GreetingWorkflow {
        @WorkflowMethod
        String getGreeting(String input);

        @UpdateMethod
        boolean checkTitleValidity();
    }

    public static class GreetingWorkflowImpl implements GreetingWorkflow {
        private final String nameWithTitle;
        private boolean titleHasBeenChecked;
        ...
        // Note the annotation is on a public constructor
        @WorkflowInit
        public GreetingWorkflowImpl(String input) {
          this.nameWithTitle = "Sir " + input;
          this.titleHasBeenChecked = false;
        }

        @Override
        public String getGreeting(String input) {
          Workflow.await(() -> titleHasBeenChecked)
          return "Hello " + nameWithTitle;
        }

        @Override
        public boolean checkTitleValidity() {
          // 👉 The handler is now guaranteed to see the workflow input
          // after it has been processed by the constructor.
          boolean isValid = activity.checkTitleValidity(nameWithTitle);
          titleHasBeenChecked = true;
          return isValid;
        }
    }
}
```

### Use locks to prevent concurrent handler execution {#control-handler-concurrency}

Concurrent processes can interact in unpredictable ways.
Incorrectly written [concurrent message-passing](/handling-messages#message-handler-concurrency) code may not work correctly when multiple handler instances run simultaneously.
Here's an example of a pathological case:

```java
public class DataWorkflowImpl implements DataWorkflow {
    ...
    @Override
    public void badSignalHandler() {
        Data data = activity.fetchData();
        this.x = data.x;
        // 🐛🐛 Bug!! If multiple instances of this method are executing concurrently, then
        // there may be times when the Workflow has self.x from one Activity execution and self.y from another.
        Workflow.sleep(Duration.ofSeconds(1));
        this.y = data.y;
    }
}
```

Coordinating access with `WorkflowLock` corrects this code.
Locking makes sure that only one handler instance can execute a specific section of code at any given time:

```java
public class DataWorkflowImpl implements DataWorkflow {
    WorkflowLock lock = Workflow.newWorkflowLock();
    ...
    @Override
    public void safeSignalHandler() {
        try {
            lock.lock();
            Data data = activity.fetchData();
            this.x = data.x;
            // ✅ OK: the scheduler may switch now to a different handler execution,
            // or to the main workflow method, but no other execution of this handler
            // can run until this execution finishes.
            Workflow.sleep(Duration.ofSeconds(1));
            this.y = data.y;
        } finally {
            lock.unlock()
        }
    }
}
```

## Message handler troubleshooting {#message-handler-troubleshooting}

When sending a Signal, Update, or Query to a Workflow, your Client might encounter the following errors:

- **The Client can't contact the server**:
  You'll receive a [`WorkflowServiceException`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowServiceException.html) on which the `cause` is a [`StatusRuntimeException`](https://grpc.github.io/grpc-java/javadoc/io/grpc/StatusRuntimeException.html) and `status` of `UNAVAILABLE` (after some retries).

- **The Workflow does not exist**:
  You'll receive a [`WorkflowNotFoundException`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowNotFoundException.html).

See [Exceptions in message handlers](/handling-messages#exceptions) for a non–Java-specific discussion of this topic.

### Problems when sending a Signal {#signal-problems}

When using Signal, the above `WorkflowException`s are the only types of exception that will result from the request.

In contrast, for Queries and Updates, the client waits for a response from the Worker.
If an issue occurs during the handler execution by the Worker, the Client may receive an exception.

### Problems when sending an Update {#update-problems}

When working with Updates, you may encounter these errors:

- **No Workflow Workers are polling the Task Queue**:
  Your request will be retried by the SDK Client indefinitely.
  You can impose a timeout with `CompletableFuture.get()` method with a timeout parameter.
  This throws a `java.util.concurrent.TimeoutException` exception when it expires.

- **Update failed**: You'll receive a `WorkflowUpdateException` exception.
  There are two ways this can happen:

  - The Update was rejected by an Update validator defined in the Workflow alongside the Update handler.

  - The Update failed after having been accepted.

  Update failures are like [Workflow failures](/references/failures).
  Issues that cause a Workflow failure in the main method also cause Update failures in the Update handler.
  These might include:

      - A failed Child Workflow
      - A failed Activity (if the Activity retries have been set to a finite number)
      - The Workflow author throwing `ApplicationFailure`
      - Any error listed in [getFailWorkflowExceptionTypes](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/worker/WorkflowImplementationOptions.html#getFailWorkflowExceptionTypes()) (empty by default)

- **The handler caused the Workflow Task to fail**:
  A [Workflow Task Failure](/references/failures) causes the server to retry Workflow Tasks indefinitely. What happens to your Update request depends on its stage:
  - If the request hasn't been accepted by the server, you receive a `FAILED_PRECONDITION` [`WorkflowServiceException`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowServiceException.html) exception.
  - If the request has been accepted, it is durable.
    Once the Workflow is healthy again after a code deploy, use an `WorkflowUpdateHandle`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowUpdateHandle.html) to fetch the Update result.

- **The Workflow finished while the Update handler execution was in progress**:
  You'll receive a [`WorkflowServiceException`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowServiceException.html) "workflow execution already completed"`.

  This will happen if the Workflow finished while the Update handler execution was in progress, for example because

  - The Workflow was canceled or failed.

  - The Workflow completed normally or continued-as-new and the Workflow author did not [wait for handlers to be finished](/handling-messages#finishing-message-handlers).

### Problems when sending a Query {#query-problems}

When working with Queries, you may encounter these errors:

- **There is no Workflow Worker polling the Task Queue**:
  You'll receive a [`WorkflowServiceException`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowServiceException.html) on which the `cause` is a [`StatusRuntimeException`](https://grpc.github.io/grpc-java/javadoc/io/grpc/StatusRuntimeException.html) with a `status` of `FAILED_PRECONDITION`.

- **Query failed**:
  You'll receive a [`WorkflowQueryException`](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowQueryException.html) exception if something goes wrong during a Query.
  Any exception in a Query handler will trigger this error.
  This differs from Signal and Update requests, where exceptions can lead to Workflow Task Failure instead.

- **The handler caused the Workflow Task to fail.**
  This would happen, for example, if the Query handler blocks the thread for too long without yielding.

## Dynamic components {#dynamic-handler}

A dynamic Workflow, Activity, Signal, Update, or Query is a kind of unnamed item.
Normally, these items are registered by name with the Worker and invoked at runtime.
When an unregistered or unrecognized Workflow, Activity, or message request arrives with a recognized method signature, the Worker can use a pre-registered dynamic stand-in.

For example, you might send a request to start a Workflow named "MyUnknownWorkflow".
After receiving a Workflow Task, the Worker may find that there's no registered Workflow Definitions of that type.
It then checks to see if there's a registered dynamic Workflow.
If the dynamic Workflow signature matches the incoming Workflow signature, the Worker invokes that just as it would invoke a non-dynamic statically named version.

By registering dynamic versions of your Temporal components, the Worker can fall back to these alternate implementations for name mismatches.

:::caution

Use dynamic elements judiciously and as a fallback mechanism, not a primary design.
They can introduce long-term maintainability and debugging issues.
Reserve dynamic invocation use for cases where a name is not or can't be known at compile time.

:::

### Set a Dynamic Workflow {#set-a-dynamic-workflow}

Use [`DynamicWorkflow`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/DynamicWorkflow.html) to implement Workflow Types dynamically.
Register a Workflow implementation type that extends `DynamicWorkflow` to implement any Workflow Type that is not explicitly registered with the Worker.

The dynamic Workflow interface is implemented with the `execute` method. This method takes in `EncodedValues` that are inputs to the Workflow Execution.
These inputs can be specified by the Client when invoking the Workflow Execution.

```java
public class MyDynamicWorkflow implements DynamicWorkflow {
   @Override
    public Object execute(EncodedValues args) {
    }
}
```

### How to set a Dynamic Activity {#set-a-dynamic-activity}

To handle Activity types that do not have an explicitly registered handler, you can directly implement a dynamic Activity.

Use `DynamicActivity` to implement any number of Activity types dynamically.
When an Activity implementation that extends `DynamicActivity` is registered, it is called for any Activity type invocation that doesn't have an explicitly registered handler.

The dynamic Activity interface is implemented with the `execute` method, as shown in the following example.

```java
// Dynamic Activity implementation
 public static class DynamicGreetingActivityImpl implements DynamicActivity {
   @Override
   public Object execute(EncodedValues args) {
     String activityType = Activity.getExecutionContext().getInfo().getActivityType();
     return activityType
         + ": "
         + args.get(0, String.class)
         + " "
         + args.get(1, String.class)
         + " from: "
         + args.get(2, String.class);
   }
 }
```

Use `Activity.getExecutionContext()` to get information about the Activity type that should be implemented dynamically.

### How to set a Dynamic Signal {#set-a-dynamic-signal}

You can also implement Signal handlers dynamically. This is useful for library-level code and implementation of DSLs.

Use `Workflow.registerListener(Object)` to register an implementation of the `DynamicSignalListener` in the Workflow implementation code.

```java
Workflow.registerListener(
  (DynamicSignalHandler)
      (signalName, encodedArgs) -> name = encodedArgs.get(0, String.class));
```

When registered, any Signals sent to the Workflow without a defined handler will be delivered to the `DynamicSignalHandler`.
Note that you can only register one `Workflow.registerListener(Object)` per Workflow Execution.
`DynamicSignalHandler` can be implemented in both regular and dynamic Workflow implementations.

### How to set a Dynamic Query {#set-a-dynamic-query}

You can also implement Query handlers dynamically. This is useful for library-level code and implementation of DSLs.

Use `Workflow.registerListener(Object)` to register an implementation of the `DynamicQueryListener` in the Workflow implementation code.

```java
Workflow.registerListener(
  (DynamicQueryHandler)
      (queryName, encodedArgs) -> name = encodedArgs.get(0, String.class));
```

When registered, any Queries sent to the Workflow without a defined handler will be delivered to the `DynamicQueryHandler`.
Note that you can only register one `Workflow.registerListener(Object)` per Workflow Execution.
`DynamicQueryHandler` can be implemented in both regular and dynamic Workflow implementations.

### How to set a Dynamic Update {#set-a-dynamic-update}

You can also implement Update handlers dynamically.
This is useful for library-level code and implementation of DSLs.

```java
Workflow.registerListener(
  (DynamicUpdateHandler)
      (updateName, encodedArgs) -> encodedArgs.get(0, String.class));
```

When registered, any Updates sent to the Workflow without a defined handler will be delivered to the `DynamicUpdateHandler`.
You can only register one `Workflow.registerListener(Object)` per Workflow Execution.
`DynamicUpdateHandler` can be implemented in both regular and dynamic Workflow implementations.

---

## Namespaces - Java SDK

This page shows how to do the following:

- [Register a Namespace](#register-namespace)
- [Manage Namespaces](#manage-namespaces)

You can create, update, deprecate or delete your [Namespaces](/namespaces) using either the Temporal CLI or SDK APIs.

Use Namespaces to isolate your Workflow Executions according to your needs.
For example, you can use Namespaces to match the development lifecycle by having separate `dev` and `prod` Namespaces.
You could also use them to ensure Workflow Executions between different teams never communicate - such as ensuring that the `teamA` Namespace never impacts the `teamB` Namespace.

On Temporal Cloud, use the [Temporal Cloud UI](/cloud/namespaces#create-a-namespace) to create and manage a Namespace from the UI, or [tcld commands](https://docs.temporal.io/cloud/tcld/namespace/) to manage Namespaces from the command-line interface.

On self-hosted Temporal Service, you can register and manage your Namespaces using the Temporal CLI (recommended) or programmatically using APIs.
Note that these APIs and Temporal CLI commands will not work with Temporal Cloud.

Use a custom [Authorizer](/self-hosted-guide/security#authorizer-plugin) on your Frontend Service in the Temporal Service to set restrictions on who can create, update, or deprecate Namespaces.

You must register a Namespace with the Temporal Service before setting it in the Temporal Client.

## Register a Namespace {#register-namespace}

**How to register a Namespace using the Java SDK.**

Registering a Namespace creates a Namespace on the Temporal Service or Temporal Cloud.

On Temporal Cloud, use the [Temporal Cloud UI](/cloud/namespaces#create-a-namespace) or [tcld commands](https://docs.temporal.io/cloud/tcld/namespace/) to create Namespaces.

On self-hosted Temporal Service, you can register your Namespaces using the Temporal CLI (recommended) or programmatically using APIs.
Note that these APIs and Temporal CLI commands will not work with Temporal Cloud.

Use a custom [Authorizer](/self-hosted-guide/security#authorizer-plugin) on your Frontend Service in the Temporal Service to set restrictions on who can create, update, or deprecate Namespaces.

Use the [`RegisterNamespace` API](https://github.com/temporalio/api/blob/f0350f8032ad2f0c60c539b3b61ea37f412f1cf7/temporal/api/workflowservice/v1/service.proto) to register a [Namespace](/namespaces) and set the [Retention Period](/temporal-service/temporal-server#retention-period) for the Workflow Execution Event History for the Namespace.

```java
//...

//...
public static void createNamespace(String name) {
    RegisterNamespaceRequest req = RegisterNamespaceRequest.newBuilder()
            .setNamespace("your-custom-namespace")
            .setWorkflowExecutionRetentionPeriod(Durations.fromDays(3)) // keeps the Workflow Execution
            //Event History for up to 3 days in the Persistence store. Not setting this value will throw an error.
            .build();
    service.blockingStub().registerNamespace(req);
}
//...
```

The Retention Period setting using `WorkflowExecutionRetentionPeriod` is mandatory.
The minimum value you can set for this period is 1 day.

Once registered, set Namespace using `WorkflowClientOptions` within a Workflow Client to run your Workflow Executions within that Namespace.
See [Connect to a Development Temporal Service](/develop/java/temporal-client#connect-to-development-service) for details.

Note that Namespace registration using this API takes up to 10 seconds to complete.
Ensure that you wait for this registration to complete before starting the Workflow Execution against the Namespace.

To update your Namespace use the [UpdateNamespace API](#manage-namespaces) with the NamespaceClient.

## Manage Namespaces {#manage-namespaces}

**How to manage Namespaces using the Java SDK.**

You can get details for your Namespaces, update Namespace configuration, and deprecate or delete your Namespaces.

On Temporal Cloud, use the [Temporal Cloud UI](/cloud/namespaces#create-a-namespace) or [tcld commands](https://docs.temporal.io/cloud/tcld/namespace/) to manage Namespaces.

On self-hosted Temporal Service, you can manage your registered Namespaces using the Temporal CLI (recommended) or programmatically using APIs.
Note that these APIs and Temporal CLI commands will not work with Temporal Cloud.

Use a custom [Authorizer](/self-hosted-guide/security#authorizer-plugin) on your Frontend Service in the Temporal Service to set restrictions on who can create, update, or deprecate Namespaces.

You must register a Namespace with the Temporal Service before setting it in the Temporal Client.

On Temporal Cloud, use the [Temporal Cloud UI](/cloud/namespaces) or [tcld commands](https://docs.temporal.io/cloud/tcld/namespace/) to manage Namespaces.

On self-hosted Temporal Service, you can manage your registered Namespaces using the Temporal CLI (recommended) or programmatically using APIs.
Note that these APIs and Temporal CLI commands will not work with Temporal Cloud.

- Update information and configuration for a registered Namespace on your Temporal Service:

  - With the Temporal CLI: [`temporal operator namespace update`](/cli/operator#update)
    Example
  - Use the [`UpdateNamespace` API](https://github.com/temporalio/api/blob/e5cf521c6fdc71c69353f3d2ac5506dd6e827af8/temporal/api/workflowservice/v1/service.proto) to update configuration on a Namespace.
    Example

  ```java

  //...
  UpdateNamespaceRequest updateNamespaceRequest = UpdateNamespaceRequest.newBuilder()
              .setNamespace("your-namespace-name") //the namespace that you want to update
              .setUpdateInfo(UpdateNamespaceInfo.newBuilder() //has options to update namespace info
                      .setDescription("your updated namespace description") //updates description in the namespace info.
                      .build())
              .setConfig(NamespaceConfig.newBuilder() //has options to update namespace configuration
                      .setWorkflowExecutionRetentionTtl(Durations.fromHours(30)) //updates the retention period for the namespace "your-namespace--name" to 30 hrs.
                      .build())
              .build();
      UpdateNamespaceResponse updateNamespaceResponse = namespaceservice.blockingStub().updateNamespace(updateNamespaceRequest);
  //...
  ```

- Get details for a registered Namespace on your Temporal Service:

  - With the Temporal CLI: [`temporal operator namespace describe`](/cli/operator#describe)
  - Use the [`DescribeNamespace` API](https://github.com/temporalio/api/blob/e5cf521c6fdc71c69353f3d2ac5506dd6e827af8/temporal/api/workflowservice/v1/service.proto) to return information and configuration details for a registered Namespace.
    Example

  ```java

  //...
  DescribeNamespaceRequest descNamespace = DescribeNamespaceRequest.newBuilder()
              .setNamespace("your-namespace-name") //specify the namespace you want details for
              .build();
      DescribeNamespaceResponse describeNamespaceResponse = namespaceservice.blockingStub().describeNamespace(descNamespace);
      System.out.println("Namespace Description: " + describeNamespaceResponse);
  //...
  ```

- Get details for all registered Namespaces on your Temporal Service:

  - With the Temporal CLI: [`temporal operator namespace list`](/cli/operator#list)
  - Use the [`ListNamespace` API](https://github.com/temporalio/api/blob/e5cf521c6fdc71c69353f3d2ac5506dd6e827af8/temporal/api/workflowservice/v1/service.proto) to return information and configuration details for all registered Namespaces on your Temporal Service.
    Example

  ```java

  //...
  ListNamespacesRequest listNamespaces = ListNamespacesRequest.newBuilder().build();
      ListNamespacesResponse listNamespacesResponse = namespaceservice.blockingStub().listNamespaces(listNamespaces); //lists 1-100 namespaces (1 page) in the active Temporal Service. To list all, set the page size or loop until NextPageToken is nil.
  //...
  ```

- Deprecate a Namespace: The [`DeprecateNamespace` API](https://github.com/temporalio/api/blob/e5cf521c6fdc71c69353f3d2ac5506dd6e827af8/temporal/api/workflowservice/v1/service.proto) updates the state of a registered Namespace to "DEPRECATED". Once a Namespace is deprecated, you cannot start new Workflow Executions on it. All existing and running Workflow Executions on a deprecated Namespace will continue to run.
  Example:

  ```java

  //...
  DeprecateNamespaceRequest deprecateNamespace = DeprecateNamespaceRequest.newBuilder()
              .setNamespace("your-namespace-name") //specify the namespace that you want to deprecate
              .build();
      DeprecateNamespaceResponse response = namespaceservice.blockingStub().deprecateNamespace(deprecateNamespace);
  //...
  ```

- Delete a Namespace: The [`DeleteNamespace` API](https://github.com/temporalio/api/blob/e5cf521c6fdc71c69353f3d2ac5506dd6e827af8/temporal/api/workflowservice/v1/service.proto) deletes a Namespace. Deleting a Namespace deletes all running and completed Workflow Executions on the Namespace, and removes them from the persistence store and the visibility store.

  Example:

  ```java
  //...
  DeleteNamespaceResponse res =
  OperatorServiceStubs.newServiceStubs(OperatorServiceStubsOptions.newBuilder()
          .setChannel(service.getRawChannel())
          .validateAndBuildWithDefaults())
      .blockingStub()
      .deleteNamespace(DeleteNamespaceRequest.newBuilder().setNamespace("your-namespace-name").build());
  //...
  ```

---

## Observability - Java SDK

The observability section of the Temporal Developer's guide covers the many ways to view the current state of your [Temporal Application](/temporal#temporal-application)—that is, ways to view which [Workflow Executions](/workflow-execution) are tracked by the [Temporal Platform](/temporal#temporal-platform) and the state of any specified Workflow Execution, either currently or at points of an execution.

This section covers features related to viewing the state of the application, including:

- [Emit metrics](#metrics)
- [Set up tracing](#tracing)
- [Log from a Workflow](#logging)
- [Visibility APIs](#visibility)

## Emit metrics {#metrics}

Each Temporal SDK is capable of emitting an optional set of metrics from either the Client or the Worker process.
For a complete list of metrics capable of being emitted, see the [SDK metrics reference](/references/sdk-metrics).

- For an overview of Prometheus and Grafana integration, refer to the [Monitoring](/self-hosted-guide/monitoring) guide.
- For a list of metrics, see the [SDK metrics reference](/references/sdk-metrics).
- For an end-to-end example that exposes metrics with the Java SDK, refer to the [samples-java](https://github.com/temporalio/samples-java/tree/main/core/src/main/java/io/temporal/samples/metrics) repo.

To emit metrics with the Java SDK, use the[`MicrometerClientStatsReporter`](https://github.com/temporalio/sdk-java/blob/55ee7894aec427d7e384c3519732bdd61119961a/src/main/java/io/temporal/common/reporter/MicrometerClientStatsReporter.java#L34) class to integrate with Micrometer MeterRegistry configured for your metrics backend.
[Micrometer](https://micrometer.io/docs) is a popular Java framework that provides integration with Prometheus and other backends.

The following example shows how to use `MicrometerClientStatsReporter` to define the metrics scope and set it with the `WorkflowServiceStubsOptions`.

```java
//...
   // see the Micrometer documentation for configuration details on other supported monitoring systems.
   // in this example shows how to set up Prometheus registry and stats reported.
   PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
   StatsReporter reporter = new MicrometerClientStatsReporter(registry);
    // set up a new scope, report every 10 seconds
     Scope scope = new RootScopeBuilder()
             .reporter(reporter)
             .reportEvery(com.uber.m3.util.Duration.ofSeconds(10));
   // for Prometheus collection, expose a scrape endpoint.
   //...
   // add metrics scope to WorkflowServiceStub options
   WorkflowServiceStubsOptions stubOptions =
       WorkflowServiceStubsOptions.newBuilder().setMetricsScope(scope).build();
//...
```

For more details, see the [Java SDK Samples](https://github.com/temporalio/samples-java/tree/637c2e66fd2dab43d9f3f39e5fd9c55e4f3884f0/core/src/main/java/io/temporal/samples/metrics).
For details on configuring a Prometheus scrape endpoint with Micrometer, see the [Micrometer Prometheus Configuring](https://docs.micrometer.io/micrometer/reference/implementations/prometheus.html#_configuring) documentation.

## Set up tracing {#tracing}

Tracing allows you to view the call graph of a Workflow along with its Activities, Nexus Operations, and any Child Workflows.

Temporal Web's tracing capabilities mainly track Activity Execution within a Temporal context. If you need custom tracing specific for your use case, you should make use of context propagation to add tracing logic accordingly.

To configure tracing in Java, register the `OpenTracingClientInterceptor()` interceptor.
You can register the interceptors on both the Temporal Client side and the Worker side.

The following code examples demonstrate the `OpenTracingClientInterceptor()` on the Temporal Client.

```java
WorkflowClientOptions.newBuilder()
   //...
   .setInterceptors(new OpenTracingClientInterceptor())
   .build();
```

```java
WorkflowClientOptions clientOptions =
    WorkflowClientOptions.newBuilder()
        .setInterceptors(new OpenTracingClientInterceptor(JaegerUtils.getJaegerOptions(type)))
        .build();
WorkflowClient client = WorkflowClient.newInstance(service, clientOptions);
```

The following code examples demonstrate the `OpenTracingClientInterceptor()` on the Worker.

```java
WorkerFactoryOptions.newBuilder()
   //...
   .setWorkerInterceptors(new OpenTracingWorkerInterceptor())
   .build();
```

```java
WorkerFactoryOptions factoryOptions =
    WorkerFactoryOptions.newBuilder()
        .setWorkerInterceptors(
            new OpenTracingWorkerInterceptor(JaegerUtils.getJaegerOptions(type)))
        .build();
WorkerFactory factory = WorkerFactory.newInstance(client, factoryOptions);
```

For more information, see the Temporal [OpenTracing module](https://github.com/temporalio/sdk-java/blob/master/temporal-opentracing/README.md).

### Context Propagation Over Nexus Operation Calls

Nexus does not use the standard context propagator header structure.
Instead, it relies on a Temporal-agnostic protocol designed to connect arbitrary systems.
To propagate context over Nexus Operation calls, the context is serialized into a `Map<String, String>`.
This map is special as it will normalize all keys to lowercase.

Because Nexus uses this custom format, and because Nexus calls may involve external systems, the `ContextPropagator` interface doesn’t apply to Nexus headers.
Context must be explicitly propagated through interceptors, as shown in the [Nexus Context Propagation sample](https://github.com/temporalio/samples-java/tree/main/core/src/main/java/io/temporal/samples/nexuscontextpropagation).

## Log from a Workflow {#logging}

Logging enables you to record critical information during code execution.
Loggers create an audit trail and capture information about your Workflow's operation.
An appropriate logging level depends on your specific needs.
During development or troubleshooting, you might use debug or even trace.
In production, you might use info or warn to avoid excessive log volume.

The logger supports the following logging levels:

| Level   | Use                                                                                                       |
| ------- | --------------------------------------------------------------------------------------------------------- |
| `TRACE` | The most detailed level of logging, used for very fine-grained information.                               |
| `DEBUG` | Detailed information, typically useful for debugging purposes.                                            |
| `INFO`  | General information about the application's operation.                                                    |
| `WARN`  | Indicates potentially harmful situations or minor issues that don't prevent the application from working. |
| `ERROR` | Indicates error conditions that might still allow the application to continue running.                    |

The Temporal SDK core normally uses `WARN` as its default logging level.

To get a standard `slf4j` logger in your Workflow code, use the [`Workflow.getLogger`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html) method.

```java
private static final Logger logger = Workflow.getLogger(DynamicDslWorkflow.class);
```

Logs in replay mode are omitted unless the [`WorkerFactoryOptions.Builder.setEnableLoggingInReplay(boolean)`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/worker/WorkerFactoryOptions.Builder.html#setEnableLoggingInReplay(boolean)) method is set to true.

### How to provide a custom logger {#custom-logger}

Use a custom logger for logging.

To set a custom logger, supply your own logging implementation and configuration details the same way you would in any other Java application.

## Visibility APIs {#visibility}

The term Visibility, within the Temporal Platform, refers to the subsystems and APIs that enable an operator to view Workflow Executions that currently exist within a Temporal Service.

### How to use Search Attributes {#search-attributes}

The typical method of retrieving a Workflow Execution is by its Workflow Id.

However, sometimes you'll want to retrieve one or more Workflow Executions based on another property. For example, imagine you want to get all Workflow Executions of a certain type that have failed within a time range, so that you can start new ones with the same arguments.

You can do this with [Search Attributes](/search-attribute).

- [Default Search Attributes](/search-attribute#default-search-attribute) like `WorkflowType`, `StartTime` and `ExecutionStatus` are automatically added to Workflow Executions.
- _Custom Search Attributes_ can contain their own domain-specific data (like `customerId` or `numItems`).
  - A few [generic Custom Search Attributes](/search-attribute#custom-search-attribute) like `CustomKeywordField` and `CustomIntField` are created by default in Temporal's [Docker Compose](https://github.com/temporalio/docker-compose).

The steps to using custom Search Attributes are:

- Create a new Search Attribute in your Temporal Service using `temporal operator search-attribute create` or the Cloud UI.
- Set the value of the Search Attribute for a Workflow Execution:
  - On the Client by including it as an option when starting the Execution.
  - In the Workflow by calling `upsertTypedSearchAttributes`.
- Read the value of the Search Attribute:
  - On the Client by calling `DescribeWorkflow`.
  - In the Workflow by looking at `WorkflowInfo`.
- Query Workflow Executions by the Search Attribute using a [List Filter](/list-filter):
  - [In the Temporal CLI](/cli/workflow#list).
  - In code by calling `ListWorkflowExecutions`.

### How to set custom Search Attributes {#custom-search-attributes}

After you've created custom Search Attributes in your Temporal Service (using `temporal operator search-attribute create` or the Cloud UI), you can set the values of the custom Search Attributes when starting a Workflow.

When starting a Workflow Execution with your Client, include the Custom Search Attribute in the options using `WorkflowOptions.newBuilder().setTypedSearchAttributes()`:

```java
    // In a shared constants file, so all files have access

    public static final SearchAttributeKey<Boolean> IS_ORDER_FAILED = SearchAttributeKey.forBoolean("isOrderFailed");
...
    // In main
    WorkflowOptions options = WorkflowOptions.newBuilder()
        .setWorkflowId(workflowID)
        .setTaskQueue(Constants.TASK_QUEUE_NAME)
        .setTypedSearchAttributes(generateSearchAttributes())
        .build();

    PizzaWorkflow workflow = client.newWorkflowStub(PizzaWorkflow.class, options);
...

    // Further down in the file
    private static Map<String, Object> generateSearchAttributes(){
        return SearchAttributes.newBuilder().set(Constants.IS_ORDER_FAILED, false).build();
    }
```

Each `SearchAttribute` object represents a custom attribute name, and the value is a [`SearchAttributeKey`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/common/SearchAttributeKey.html#forBoolean(java.lang.String)) representing a specific type. Currently the following types are supported:

- Boolean
- Double
- Long
- KeyWord
- KeyWordList
- Text

In this example `isOrderFailed` is set as a Search Attribute. This attribute is
useful for querying Workflows based the success/failure of customer orders.

### How to upsert Search Attributes {#upsert-search-attributes}

Within the Workflow code, you can dynamically add or update Search Attributes using [`upsertTypedSearchAttributes`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html#upsertTypedSearchAttributes(io.temporal.common.SearchAttributeUpdate...)).
This method is particularly useful for Workflows whose attributes need to change based on internal logic or external events.

```java

  ...

  // Existing Workflow Logic

  Map<String, Object> searchAttribute = new HashMap<>();

  Distance distance;
  try {
    distance = activities.getDistance(address);
    searchAttribute.put("isOrderFailed", false);
    Workflow.upsertTypedSearchAttributes(Constants.IS_ORDER_FAILED.valueSet(false));
  } catch (NullPointerException e) {
    searchAttribute.put("isOrderFailed", true);
    Workflow.upsertTypedSearchAttributes(Constants.IS_ORDER_FAILED.valueSet(true));
    throw new NullPointerException("Unable to get distance");
  }
```

### How to remove a Search Attribute from a Workflow {#remove-search-attribute}

To remove a Search Attribute that was previously set, set it to an empty Map.

```java
    // In a shared constants file, so all files have access

    public static final SearchAttributeKey<Boolean> IS_ORDER_FAILED = SearchAttributeKey.forBoolean("isOrderFailed");

    ...

    Workflow.upsertTypedSearchAttributes(Constants.IS_ORDER_FAILED.valueUnset());
```

---

## Schedules - Java SDK

This page shows how to do the following:

- [How to Schedule a Workflow](#schedule-a-workflow)
  - [How to create a Schedule in Java](#create-schedule)
  - [How to backfill a Schedule in Java](#backfill-schedule)
  - [How to delete a Schedule in Java](#delete-schedule)
  - [How to describe a Schedule in Java](#describe-schedule)
  - [How to list a Schedule in Java](#list-schedule)
  - [How to pause a Schedule in Java](#pause-schedule)
  - [How to trigger a Schedule in Java](#trigger-schedule)
  - [How to update a Schedule in Java](#update-schedule)
- [How to set a Cron Schedule in Java](#cron-schedule)
- [Start Delay](#start-delay)

## How to Schedule a Workflow {#schedule-a-workflow}

Scheduling Workflows is a crucial aspect of any automation process, especially when dealing with time-sensitive tasks. By scheduling a Workflow, you can automate repetitive tasks, reduce the need for manual intervention, and ensure timely execution of your business processes

Use any of the following action to help Schedule a Workflow Execution and take control over your automation process.

### How to create a Schedule in Java {#create-schedule}

The create action enables you to create a new Schedule. When you create a new Schedule, a unique Schedule ID is generated, which you can use to reference the Schedule in other Schedule commands.

To create a Scheduled Workflow Execution in Java, use the `createSchedule()` method on the `ScheduleClient`. Schedules must be initialized with a Schedule ID,

```java
Schedule schedule =
    Schedule.newBuilder()
        .setAction(
            ScheduleActionStartWorkflow.newBuilder()
                .setWorkflowType(HelloSchedules.GreetingWorkflow.class)
                .setArguments("World")
                .setOptions(
                    WorkflowOptions.newBuilder()
                        .setWorkflowId("WorkflowId")
                        .setTaskQueue("TaskQueue")
                        .build())
                .build())
        .setSpec(ScheduleSpec.newBuilder().build())
        .build();

// Create a schedule on the server
ScheduleHandle handle =
    scheduleClient.createSchedule("ScheduleId", schedule, ScheduleOptions.newBuilder().build());
```

:::tip Schedule Auto-Deletion

Once a Schedule has completed creating all its Workflow Executions, the Temporal Service deletes it since it won’t fire again.
The Temporal Service doesn't guarantee when this removal will happen.

:::

### How to backfill a Schedule in Java {#backfill-schedule}

The backfill action executes Actions ahead of their specified time range. This command is useful when you need to execute a missed or delayed Action, or when you want to test the Workflow before its scheduled time.

To Backfill a Scheduled Workflow Execution in Java, use the `backfill()` method on the `ScheduleHandle`.

```java
ScheduleHandle handle = client.getHandle("schedule-id")

Instant now = Instant.now();
handle.backfill(
    Arrays.asList(
        new ScheduleBackfill(now.minusMillis(5500), now.minusMillis(2500)),
        new ScheduleBackfill(now.minusMillis(2500), now)));
```

### How to delete a Schedule in Java {#delete-schedule}

The delete action enables you to delete a Schedule. When you delete a Schedule, it does not affect any Workflows that were started by the Schedule.

To delete a Scheduled Workflow Execution in Java, use the `delete()` method on the `Schedule Handle`.

```java
ScheduleHandle handle = client.getHandle("schedule-id")
handle.delete();
```

### How to describe a Schedule in Java {#describe-schedule}

The describe action shows the current Schedule configuration, including information about past, current, and future Workflow Runs. This command is helpful when you want to get a detailed view of the Schedule and its associated Workflow Runs.

To describe a Scheduled Workflow Execution in Java, use the `describe()` method on the `ScheduleHandle`.

```java
ScheduleHandle handle = client.getHandle("schedule-id")
ScheduleDescription description = handle.describe();
```

### How to list a Schedule in Java {#list-schedule}

The list action lists all the available Schedules. This command is useful when you want to view a list of all the Schedules and their respective Schedule IDs.

To list all schedules, use the `listSchedules()` asynchronous method on the `ScheduleClient`.
If a schedule is added or deleted, it may not be available in the list immediately.

```java
Stream<ScheduleListDescription> scheduleStream = client.listSchedules();
```

### How to pause a Schedule in Java {#pause-schedule}

The pause action enables you to pause and unpause a Schedule. When you pause a Schedule, all the future Workflow Runs associated with the Schedule are temporarily stopped. This command is useful when you want to temporarily halt a Workflow due to maintenance or any other reason.

To pause a Scheduled Workflow Execution in Java, use the `pause()` method on the `ScheduleHandle`.
You can pass a `note` to the `pause()` method to provide a reason for pausing the schedule.

```java
ScheduleHandle handle = client.getHandle("schedule-id")
handle.pause("Pausing the schedule for now");
```

### How to trigger a Schedule in Java {#trigger-schedule}

The trigger action triggers an immediate action with a given Schedule. By default, this action is subject to the Overlap Policy of the Schedule. This command is helpful when you want to execute a Workflow outside of its scheduled time.

To trigger a Scheduled Workflow Execution in Java, use the `trigger()` method on the `ScheduleHandle`.

```java
ScheduleHandle handle = client.getHandle("schedule-id")
handle.trigger();
```

### How to update a Schedule in Java {#update-schedule}

The update action enables you to update an existing Schedule. This command is useful when you need to modify the Schedule's configuration, such as changing the start time, end time, or interval.

Create a function that takes `ScheduleUpdateInput` and returns `ScheduleUpdate`.
To update a Schedule, use a callback to build the update from the description.
The following example updates the Schedule to set a limited number of actions.

```java
ScheduleHandle handle = client.getHandle("schedule-id")
handle.update(
    (ScheduleUpdateInput input) -> {
      Schedule.Builder builder = Schedule.newBuilder(input.getDescription().getSchedule());
      // Make the schedule paused to demonstrate how to unpause a schedule
      builder.setState(
          ScheduleState.newBuilder()
              .setLimitedAction(true)
              .setRemainingActions(10)
              .build());
      return new ScheduleUpdate(builder.build());
    });
```

## How to set a Cron Schedule in Java {#cron-schedule}

:::caution Cron support is not recommended

We recommend using [Schedules](https://docs.temporal.io/schedule) instead of Cron Jobs.
Schedules were built to provide a better developer experience, including more configuration options and the ability to update or pause running Schedules.

:::

A [Temporal Cron Job](/cron-job) is the series of Workflow Executions that occur when a Cron Schedule is provided in the call to spawn a Workflow Execution.

A Cron Schedule is provided as an option when the call to spawn a Workflow Execution is made.

Set the Cron Schedule with the [`WorkflowStub`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html) instance in the Client code using [`WorkflowOptions.Builder.setCronSchedule`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowOptions.Builder.html).

Setting `setCronSchedule` changes the Workflow Execution into a Temporal Cron Job.
The default timezone for a Cron is UTC.

- Type: `String`
- Default: None

```java
//create Workflow stub for YourWorkflowInterface
YourWorkflowInterface workflow1 =
    YourWorker.yourclient.newWorkflowStub(
        YourWorkflowInterface.class,
        WorkflowOptions.newBuilder()
                .setWorkflowId("YourWF")
                .setTaskQueue(YourWorker.TASK_QUEUE)
                // Set Cron Schedule
                .setCronSchedule("* * * * *")
                .build());
```

Temporal Workflow Schedule Cron strings follow this format:

```
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of the month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday)
│ │ │ │ │
* * * * *
```

For more details, see the [Cron Sample](https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/hello/HelloCron.java)

## Start Delay {#start-delay}

**How to delay the start of a Workflow Execution using Start Delay with the Temporal Java SDK.**

Use the `StartDelay` to schedule a Workflow Execution at a specific one-time future point rather than on a recurring schedule.

Create an instance of [`WorkflowStub`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/WorkflowStub.html) in the Client code and set `StartDelay` using `setStartDelay`.

```java
//create Workflow stub for YourWorkflowInterface
YourWorkflowInterface workflow1 =
    WorkerGreet.greetclient.newWorkflowStub(
        GreetWorkflowInterface.class,
        WorkflowOptions.newBuilder()
                .setWorkflowId("YourWorkflow")
                .setTaskQueue(WorkerGreet.TASK_QUEUE)
                // Start the workflow in 12 hours
                .setStartDelay(Duration.ofHours(12))
                .build());
```

---

## Set up your local with the Java SDK