Master Long‑Running Workflows in Spring Boot 3 with Temporal

This article walks through building a robust, long‑running order‑processing workflow in Spring Boot 3 using the open‑source Temporal workflow engine, covering environment setup, Maven dependencies, configuration, workflow and activity definitions, service and controller code, and testing of retry and recovery features.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Master Long‑Running Workflows in Spring Boot 3 with Temporal

Introduction

In enterprise Spring Boot applications, long‑running tasks such as order processing and payment settlement often suffer from fragile scheduling, duplicated retry logic, and tangled state management, leading to poor stability and high maintenance cost.

What is Temporal?

Temporal is an open‑source distributed workflow engine that lets developers model complex business logic as code‑defined workflows. It provides reliable event‑driven execution, automatic state persistence, built‑in retry policies, and structured state storage, eliminating the need for custom timers, database flags, or manual compensation logic.

Use‑Case Overview

The example implements an order‑processing workflow with the following steps:

Validate order

Charge payment

Reserve inventory

Notify shipping

Send confirmation email

Each step may take time or fail, requiring robust handling.

1. Environment Preparation

Download the Temporal server from the official site and start it in development mode: temporal server start-dev Optionally change the UI port: temporal server start-dev --ui-port 8080 To persist data between restarts, specify a database file:

temporal server start-dev --db-filename pack.db
Temporal UI
Temporal UI

2. Add Maven Dependency

<dependency>
  <groupId>io.temporal</groupId>
  <artifactId>temporal-spring-boot-starter</artifactId>
  <version>1.30.1</version>
</dependency>

3. Configuration

spring:
  temporal:
    namespace: default
    connection:
      target: 127.0.0.1:7233
      enable-https: false
    workers:
    - name: order-process-worker
      task-queue: order-process-queue
    workersAutoDiscovery:
      packages:
      - com.pack

4. Define the Workflow

@WorkflowInterface
public interface OrderWorkflow {
    @WorkflowMethod
    void processOrder(String orderId);
}

5. Implement the Workflow

@WorkflowImpl(workers = "order-process-worker")
public class OrderWorkflowImpl implements OrderWorkflow {
    private final Activities activities = Workflow.newActivityStub(
        Activities.class,
        ActivityOptions.newBuilder()
            .setStartToCloseTimeout(Duration.ofMinutes(1))
            .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(5).build())
            .build());

    @Override
    public void processOrder(String orderId) {
        activities.validateOrder(orderId);
        activities.chargePayment(orderId);
        activities.reserveInventory(orderId);
        activities.notifyShipping(orderId);
        activities.sendConfirmationEmail(orderId);
    }
}

6. Define Activities

@ActivityInterface
public interface Activities {
    @ActivityMethod
    void validateOrder(String orderId);
    @ActivityMethod
    void chargePayment(String orderId);
    @ActivityMethod
    void reserveInventory(String orderId);
    @ActivityMethod
    void notifyShipping(String orderId);
    @ActivityMethod
    void sendConfirmationEmail(String orderId);
}

7. Implement Activities

@Component
@ActivityImpl(workers = "order-process-worker")
public class ActivitiesImpl implements Activities {
    @Override
    public void validateOrder(String orderId) {
        System.out.printf("验证订单【%s】%n", orderId);
    }
    @Override
    public void chargePayment(String orderId) {
        System.out.printf("付款扣费【%s】%n", orderId);
    }
    @Override
    public void reserveInventory(String orderId) {
        System.out.printf("预留商品库存【%s】%n", orderId);
        try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) {}
    }
    @Override
    public void notifyShipping(String orderId) {
        System.out.printf("通知物流供应商【%s】%n", orderId);
        try { TimeUnit.SECONDS.sleep(30); } catch (InterruptedException e) {}
    }
    @Override
    public void sendConfirmationEmail(String orderId) {
        System.out.printf("向客户发送确认邮件【%s】%n", orderId);
    }
}

8. Start the Workflow

@Service
public class OrderService {
    private final WorkflowClient workflowClient;
    public OrderService(WorkflowClient workflowClient) { this.workflowClient = workflowClient; }
    public void startWorkflow(String orderId) {
        OrderWorkflow workflow = workflowClient.newWorkflowStub(
            OrderWorkflow.class,
            WorkflowOptions.newBuilder().setTaskQueue("order-process-queue").build());
        WorkflowClient.start(workflow::processOrder, orderId);
    }
}

9. Expose via Controller

@RestController
@RequestMapping("/orders")
public class OrderController {
    private final OrderService orderService;
    public OrderController(OrderService orderService) { this.orderService = orderService; }
    @GetMapping("/process")
    public ResponseEntity<?> process() {
        orderService.startWorkflow("xxxooo");
        return ResponseEntity.ok("success");
    }
}

10. Testing and Retry Demonstration

Calling /orders/process returns immediately while the workflow runs asynchronously. The Temporal UI shows the workflow progress. If the Temporal server is stopped during a long‑running activity, the built‑in retry policy automatically resumes the activity when the server is restarted, continuing from the last successful step.

Retry UI
Retry UI

Conclusion

Temporal together with Spring Boot provides a powerful, fault‑tolerant solution for long‑running business processes, eliminating boilerplate retry, state‑tracking, and compensation code, and allowing developers to focus on core business logic.

Javamicroservicesbackend developmentSpring BootTemporal
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.