Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cadence-workflow/cadence/llms.txt

Use this file to discover all available pages before exploring further.

Introduction

The Cadence Java SDK is the official client library for building workflows and activities in Java and other JVM languages. It provides annotation-based workflow definitions, Spring Boot integration, and comprehensive tooling for enterprise applications.

GitHub Repository

Official Cadence Java Client SDK - Star and contribute on GitHub

Installation

Prerequisites

  • Java 8 or higher (Java 11+ recommended)
  • Maven 3.6+ or Gradle 6.0+
  • Cadence server running (local or remote)

Maven Setup

Add the Cadence Java client dependency to your pom.xml:
pom.xml
<dependencies>
    <dependency>
        <groupId>com.uber.cadence</groupId>
        <artifactId>cadence-client</artifactId>
        <version>3.11.2</version>
    </dependency>
</dependencies>

Gradle Setup

Add the dependency to your build.gradle:
dependencies {
    implementation 'com.uber.cadence:cadence-client:3.11.2'
}

Quick Start

1. Define a Workflow Interface

Workflow interfaces define the contract for workflow execution:
import com.uber.cadence.workflow.WorkflowMethod;
import com.uber.cadence.workflow.SignalMethod;
import com.uber.cadence.workflow.QueryMethod;

public interface HelloWorkflow {
    
    @WorkflowMethod(executionStartToCloseTimeoutSeconds = 600)
    String sayHello(String name);
    
    @SignalMethod
    void updateGreeting(String greeting);
    
    @QueryMethod
    int getCallCount();
}

2. Implement the Workflow

Workflow implementations must be deterministic:
import com.uber.cadence.workflow.Workflow;
import com.uber.cadence.activity.ActivityOptions;
import java.time.Duration;

public class HelloWorkflowImpl implements HelloWorkflow {
    
    private String greeting = "Hello";
    private int callCount = 0;
    
    // Configure activity options
    private final ActivityOptions activityOptions = new ActivityOptions.Builder()
        .setScheduleToStartTimeout(Duration.ofMinutes(1))
        .setStartToCloseTimeout(Duration.ofMinutes(5))
        .setHeartbeatTimeout(Duration.ofSeconds(20))
        .build();
    
    // Create activity stub
    private final GreetingActivities activities = 
        Workflow.newActivityStub(GreetingActivities.class, activityOptions);
    
    @Override
    public String sayHello(String name) {
        callCount++;
        
        // Execute activity
        String result = activities.greet(greeting, name);
        
        // Workflow can also use timers
        Workflow.sleep(Duration.ofSeconds(1));
        
        return result;
    }
    
    @Override
    public void updateGreeting(String greeting) {
        this.greeting = greeting;
    }
    
    @Override
    public int getCallCount() {
        return callCount;
    }
}

3. Define Activity Interface

Activities perform non-deterministic operations:
import com.uber.cadence.activity.ActivityMethod;

public interface GreetingActivities {
    
    @ActivityMethod(scheduleToCloseTimeoutSeconds = 300)
    String greet(String greeting, String name);
    
    @ActivityMethod
    void sendEmail(String to, String message);
}

4. Implement Activities

Activity implementations can call external services:
import com.uber.cadence.activity.Activity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class GreetingActivitiesImpl implements GreetingActivities {
    
    private static final Logger logger = 
        LoggerFactory.getLogger(GreetingActivitiesImpl.class);
    
    @Override
    public String greet(String greeting, String name) {
        // Activities can call external services
        logger.info("Greeting {} with {}", name, greeting);
        
        // Record heartbeat for long-running activities
        Activity.getExecutionContext().heartbeat(null);
        
        return String.format("%s, %s!", greeting, name);
    }
    
    @Override
    public void sendEmail(String to, String message) {
        // Call email service
        logger.info("Sending email to {} with message: {}", to, message);
    }
}

5. Configure and Start Worker

Workers poll for and execute workflows and activities:
import com.uber.cadence.client.WorkflowClient;
import com.uber.cadence.serviceclient.ClientOptions;
import com.uber.cadence.serviceclient.WorkflowServiceTChannel;
import com.uber.cadence.worker.Worker;
import com.uber.cadence.worker.WorkerFactory;
import com.uber.cadence.worker.WorkerOptions;

public class WorkerMain {
    
    private static final String DOMAIN = "my-domain";
    private static final String TASK_LIST = "my-task-list";
    
    public static void main(String[] args) {
        // Create Cadence service client
        WorkflowServiceTChannel service = new WorkflowServiceTChannel(
            ClientOptions.newBuilder()
                .setHost("localhost")
                .setPort(7933)
                .build()
        );
        
        // Create workflow client
        WorkflowClient workflowClient = WorkflowClient.newInstance(
            service,
            WorkflowClient.Options.newBuilder()
                .setDomain(DOMAIN)
                .build()
        );
        
        // Create worker factory
        WorkerFactory factory = WorkerFactory.newInstance(workflowClient);
        
        // Configure worker
        WorkerOptions workerOptions = WorkerOptions.newBuilder()
            .setMaxConcurrentActivityExecutionSize(100)
            .setMaxConcurrentWorkflowExecutionSize(50)
            .build();
        
        Worker worker = factory.newWorker(TASK_LIST, workerOptions);
        
        // Register workflow implementation
        worker.registerWorkflowImplementationTypes(HelloWorkflowImpl.class);
        
        // Register activity implementation
        worker.registerActivitiesImplementations(new GreetingActivitiesImpl());
        
        // Start worker
        factory.start();
        
        System.out.println("Worker started for task list: " + TASK_LIST);
    }
}

6. Execute Workflow

Start workflow execution from your application:
import com.uber.cadence.client.WorkflowClient;
import com.uber.cadence.client.WorkflowOptions;
import com.uber.cadence.serviceclient.ClientOptions;
import com.uber.cadence.serviceclient.WorkflowServiceTChannel;
import java.time.Duration;

public class WorkflowStarter {
    
    public static void main(String[] args) {
        // Create service client
        WorkflowServiceTChannel service = new WorkflowServiceTChannel(
            ClientOptions.newBuilder()
                .setHost("localhost")
                .setPort(7933)
                .build()
        );
        
        // Create workflow client
        WorkflowClient workflowClient = WorkflowClient.newInstance(
            service,
            WorkflowClient.Options.newBuilder()
                .setDomain("my-domain")
                .build()
        );
        
        // Configure workflow options
        WorkflowOptions workflowOptions = new WorkflowOptions.Builder()
            .setWorkflowId("hello-workflow-1")
            .setTaskList("my-task-list")
            .setExecutionStartToCloseTimeout(Duration.ofMinutes(10))
            .build();
        
        // Create workflow stub
        HelloWorkflow workflow = workflowClient.newWorkflowStub(
            HelloWorkflow.class,
            workflowOptions
        );
        
        // Start workflow execution
        String result = workflow.sayHello("World");
        
        System.out.println("Workflow result: " + result);
    }
}

Advanced Patterns

Child Workflows

Compose complex workflows from simpler ones:
import com.uber.cadence.workflow.Workflow;
import com.uber.cadence.workflow.ChildWorkflowOptions;
import java.time.Duration;

public class ParentWorkflowImpl implements ParentWorkflow {
    
    @Override
    public String orchestrate(String input) {
        // Configure child workflow options
        ChildWorkflowOptions childOptions = new ChildWorkflowOptions.Builder()
            .setExecutionStartToCloseTimeout(Duration.ofHours(1))
            .setTaskList("child-task-list")
            .build();
        
        // Create child workflow stub
        ChildWorkflow child = Workflow.newChildWorkflowStub(
            ChildWorkflow.class,
            childOptions
        );
        
        // Execute child workflow
        String childResult = child.processData(input);
        
        return "Parent processed: " + childResult;
    }
}

Saga Pattern

Implement distributed transactions with compensation:
import com.uber.cadence.workflow.Workflow;
import com.uber.cadence.workflow.Saga;
import io.temporal.common.CancellationScope;

public class SagaWorkflowImpl implements SagaWorkflow {
    
    private final BookingActivities activities = 
        Workflow.newActivityStub(BookingActivities.class);
    
    @Override
    public void bookTrip(String userId, String flightId, String hotelId) {
        Saga saga = new Saga(new Saga.Options.Builder()
            .setParallelCompensation(false)
            .build());
        
        try {
            // Book flight
            String flightBookingId = activities.bookFlight(flightId, userId);
            saga.addCompensation(() -> 
                activities.cancelFlight(flightBookingId)
            );
            
            // Book hotel
            String hotelBookingId = activities.bookHotel(hotelId, userId);
            saga.addCompensation(() -> 
                activities.cancelHotel(hotelBookingId)
            );
            
            // Charge payment
            activities.chargePayment(userId, calculateTotal());
            saga.addCompensation(() -> 
                activities.refundPayment(userId)
            );
            
        } catch (Exception e) {
            // Compensate on failure
            saga.compensate();
            throw e;
        }
    }
    
    private double calculateTotal() {
        return 1000.0; // Simplified
    }
}

Signals and Queries

public class OrderWorkflowImpl implements OrderWorkflow {
    
    private String status = "PENDING";
    private boolean approved = false;
    
    @Override
    public void processOrder(String orderId) {
        // Wait for approval signal
        Workflow.await(() -> approved);
        
        status = "APPROVED";
        // Continue processing...
    }
    
    @Override
    public void approveOrder() {
        this.approved = true;
    }
    
    @Override
    public String getStatus() {
        return status;
    }
}

// Send signal from client
OrderWorkflow workflow = workflowClient.newWorkflowStub(
    OrderWorkflow.class,
    "order-workflow-id"
);
workflow.approveOrder();

Retry Policies

Configure automatic retries for activities:
import com.uber.cadence.common.RetryOptions;
import java.time.Duration;

public class RobustWorkflowImpl implements RobustWorkflow {
    
    private final RetryOptions retryOptions = new RetryOptions.Builder()
        .setInitialInterval(Duration.ofSeconds(1))
        .setMaximumInterval(Duration.ofMinutes(1))
        .setBackoffCoefficient(2.0)
        .setMaximumAttempts(5)
        .setDoNotRetry(IllegalArgumentException.class)
        .build();
    
    private final ActivityOptions activityOptions = new ActivityOptions.Builder()
        .setStartToCloseTimeout(Duration.ofMinutes(5))
        .setRetryOptions(retryOptions)
        .build();
    
    private final RiskyActivities activities = 
        Workflow.newActivityStub(RiskyActivities.class, activityOptions);
    
    @Override
    public void executeRiskyOperation() {
        // Activity will be automatically retried on failure
        activities.riskyCall();
    }
}

Spring Boot Integration

Spring Configuration

import com.uber.cadence.client.WorkflowClient;
import com.uber.cadence.serviceclient.ClientOptions;
import com.uber.cadence.serviceclient.WorkflowServiceTChannel;
import com.uber.cadence.worker.WorkerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CadenceConfiguration {
    
    @Value("${cadence.service.host:localhost}")
    private String cadenceHost;
    
    @Value("${cadence.service.port:7933}")
    private int cadencePort;
    
    @Value("${cadence.domain}")
    private String domain;
    
    @Bean
    public WorkflowServiceTChannel workflowService() {
        return new WorkflowServiceTChannel(
            ClientOptions.newBuilder()
                .setHost(cadenceHost)
                .setPort(cadencePort)
                .build()
        );
    }
    
    @Bean
    public WorkflowClient workflowClient(WorkflowServiceTChannel service) {
        return WorkflowClient.newInstance(
            service,
            WorkflowClient.Options.newBuilder()
                .setDomain(domain)
                .build()
        );
    }
    
    @Bean
    public WorkerFactory workerFactory(WorkflowClient workflowClient) {
        return WorkerFactory.newInstance(workflowClient);
    }
}

Spring Worker Component

import com.uber.cadence.worker.Worker;
import com.uber.cadence.worker.WorkerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class CadenceWorker implements CommandLineRunner {
    
    @Autowired
    private WorkerFactory workerFactory;
    
    @Autowired
    private GreetingActivitiesImpl activities;
    
    @Override
    public void run(String... args) {
        Worker worker = workerFactory.newWorker("my-task-list");
        
        worker.registerWorkflowImplementationTypes(HelloWorkflowImpl.class);
        worker.registerActivitiesImplementations(activities);
        
        workerFactory.start();
    }
}

Testing

Unit Testing Workflows

import com.uber.cadence.testing.TestWorkflowEnvironment;
import com.uber.cadence.worker.Worker;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;

public class HelloWorkflowTest {
    
    private TestWorkflowEnvironment testEnv;
    private Worker worker;
    
    @Before
    public void setUp() {
        testEnv = TestWorkflowEnvironment.newInstance();
        worker = testEnv.newWorker("test-task-list");
        
        // Register workflow
        worker.registerWorkflowImplementationTypes(HelloWorkflowImpl.class);
    }
    
    @After
    public void tearDown() {
        testEnv.close();
    }
    
    @Test
    public void testWorkflow() {
        // Mock activities
        GreetingActivities activities = mock(GreetingActivities.class);
        when(activities.greet("Hello", "World"))
            .thenReturn("Hello, World!");
        worker.registerActivitiesImplementations(activities);
        
        // Start test environment
        testEnv.start();
        
        // Create workflow stub
        HelloWorkflow workflow = testEnv.newWorkflowStub(HelloWorkflow.class);
        
        // Execute workflow
        String result = workflow.sayHello("World");
        
        // Verify result
        assertEquals("Hello, World!", result);
        verify(activities).greet("Hello", "World");
    }
}

Sample Repository

Cadence Java Samples

Enterprise examples including:
  • Spring Boot integration
  • Saga pattern implementation
  • Complex orchestration scenarios
  • Testing strategies
  • Production configurations

Best Practices

  • Keep workflow code deterministic
  • Use Workflow.getVersion() for versioning
  • Avoid direct instantiation of random or time
  • Use workflow methods for all non-deterministic operations
  • Make activities idempotent when possible
  • Implement heartbeats for long-running activities
  • Use dependency injection for testability
  • Handle exceptions appropriately
  • Use Spring’s dependency injection for activities
  • Configure workers as Spring components
  • Externalize configuration to application.properties
  • Implement health checks for workers
  • Adjust worker pool sizes based on load
  • Use local activities for fast operations
  • Enable sticky execution for better performance
  • Monitor metrics and adjust accordingly

Next Steps

Core Concepts

Understand workflows, activities, and task lists

Go Client

Explore the Go SDK for cloud-native apps

CLI Reference

Manage workflows with the Cadence CLI

Operations

Monitor and operate Cadence in production

Build docs developers (and LLMs) love