Temporal Java SDK Samples

repository·main·Indexed 42 days ago

https://github.com/temporalio/samples-java

A collection of sample implementations demonstrating the capabilities of the Temporal Java SDK. Examples include core SDK features, API Key authentication for Temporal Cloud, asynchronous child workflows, auto-heartbeating utilities, batch processing patterns (Iterator and Sliding Window), and SAGA pattern implementations for trip booking.

Tokens
34.5K
Snippets
109
Records
156
Agent score
52%

What's inside Temporal Java SDK Samples

  1. Overview of Temporal Java SDK Samples

    main

    This repository provides practical examples of using the Temporal Java SDK. It is organized into several modules targeting different integration patterns:

    • Core: Demonstrates fundamental SDK features.
    • SpringBoot: Showcases integration with Spring Boot autoconfiguration.
    • SpringBoot Basic: A minimal Spring Boot autoconfiguration example with no external dependencies.
    • Spring AI: Demonstrates durable AI agents using chat models, tools, MCP servers, vector stores, and embeddings via the Temporal Spring AI integration.
    • Lambda Worker: Shows how to run a Temporal Java Worker within an AWS Lambda environment.
  2. Explore Polling Best Practices in Temporal Java Samples

    main

    This directory contains samples demonstrating three distinct architectural patterns for implementing polling using the Temporal Java SDK. Depending on your use case (frequency and scale), you should choose one of the following patterns:

    1. Frequently Polling Activity: Best for scenarios where an activity needs to check a status or resource very often.
    2. Infrequently Polling Activity: Best for scenarios where polling happens at longer intervals.
    3. Periodic Polling of a sequence of activities: Best for orchestrating a sequence of activities that are triggered periodically.

    These patterns are based on community-recommended best practices for managing polling logic within Temporal workflows.

  3. Expose Workflows as Nexus operations using different patterns

    main

    This sample demonstrates how to expose a long-running Temporal Workflow's queries, updates, and signals as Nexus operations. It provides two distinct architectural patterns depending on whether the caller needs to manage the Workflow lifecycle or simply interact with an existing one.

    Pattern 1: Caller Pattern (callerpattern/)

    Use this pattern when you want to signal an existing Workflow that is already running.

    • Workflow Creation: The handler worker starts the Workflow automatically on boot.
    • Workflow ID Management: Only the handler knows the Workflow ID; the caller interacts with the Nexus service without needing to know the specific ID.
    • Nexus Service: Implemented via NexusGreetingService.

    Pattern 2: On-Demand Pattern (ondemandpattern/)

    Use this pattern when you want to create and run Workflows on demand and then send signals to them.

    • Workflow Creation: The caller starts the Workflow by invoking a Nexus operation.
    • Workflow ID Management: The caller chooses and passes the Workflow ID in every operation.
    • Nexus Service: Implemented via NexusRemoteGreetingService.

    In both patterns, the core Workflow logic (GreetingWorkflow, GreetingWorkflowImpl) and Activities (GreetingActivity, GreetingActivityImpl) remain consistent; only the Nexus service interface and implementation change to accommodate the different lifecycle requirements.

  4. Customize Spring Boot Temporal options

    main

    This sample demonstrates how to optimize and override default Temporal configuration options within a Spring Boot application. Specifically, it shows how to customize:

    • WorkflowServiceStubsOptions
    • WorkflowClientOption
    • WorkerFactoryOptions
    • WorkerOptions

    Note that WorkerOptions can be optimized on a per-worker or per-task-queue basis.

    In this specific sample, the worker is configured as a "local activity worker" via custom options, meaning it is configured not to poll for activity tasks. The sample workflow demonstrates this by attempting to invoke an activity as a "normal" activity (which fails/times out) and then successfully invoking it as a local activity.

  5. Overview of Core Temporal Java SDK Sample Categories

    main

    The core samples demonstrate various Temporal primitives and advanced patterns:

    Hello Samples (Primitives)

    • Signals & Updates: HelloSignal, HelloUpdate, HelloAccumulator (accumulating signals), HelloSignalWithTimer (processing last signal after a duration).
    • Activities: HelloActivity, HelloActivityRetry, HelloAsync (using Promises), HelloParallelActivity (Promise.allOf), HelloLocalActivity, HelloStandaloneActivity (running without a Workflow).
    • Control Flow: HelloAwait (waiting for conditions), HelloCancellationScope (explicit cancellation), HelloChild (child workflows), HelloCron (scheduled workflows), HelloSaga (SAGA pattern).
    • State & Query: HelloQuery (querying workflow state), HelloSearchAttributes (custom search attributes).
    • Advanced: HelloDynamic (DynamicWorkflow/DynamicActivity), HelloPeriodic (Continue-As-New), HelloSideEffect (Side Effects).

    Scenario-based Samples

    • Complex Workflows: Booking SAGA (trip booking), Money Transfer, Money Batch (using Signal with start).
    • Batch Processing: Iterator Batch, Sliding Window Batch, Heartbeating Activity Batch.
    • Infrastructure: Worker Versioning, Lambda Worker (AWS Lambda), Environment Configuration (TOML files).

    API & Integration Demonstrations

    • Security: Configure WorkflowClient to use mTLS, Configure WorkflowClient to use API Key, Encrypted Payloads.
    • Observability: Set up SDK metrics, Set up OpenTracing/OpenTelemetry with Jaeger.
    • Nexus: Demonstrates Nexus operations, messaging, and context propagation.
  6. How updatable timers work using Workflow.await

    main

    The Updatable Timer sample demonstrates a pattern for implementing a sleep mechanism that is not fixed. Instead of using a standard sleep, it uses a helper class relying on Workflow.await to block until a specific time is reached.

    Because the sleep is based on Workflow.await, the workflow can be interrupted or updated by sending a Signal (specifically updateWakeUpTime). When a signal is received, the target wake-up time is updated, and Workflow.await re-evaluates the condition, allowing the workflow to 'sleep' for a new, adjusted duration.

  7. What are Workflow Streams?

    main

    A workflow stream is a durable publish/subscribe log hosted inside a Temporal workflow. It is provided by the experimental io.temporal:temporal-workflowstreams contrib module.

    Core Mechanics

    • Publishing: External code (activities, starters, or other workflows) publishes messages to named topics using signals.
    • Subscribing: Clients long-poll for new items via updates.
    • Offset Management: A query exposes the current offset. Offsets are global across all topics within a stream.
    • Guarantees: Because it is backed by Temporal's durable execution, delivery is ordered, durable, and exactly-once. It supports client-side batching, publisher deduplication, continue-as-new survival, and truncation.

    Note: The temporal-workflowstreams module is experimental and requires SDK 1.37.0 or later.

  8. Implement a Custom Crypto Payload Converter

    main

    This sample demonstrates how to override the default JSON converter in the Temporal Java SDK to encrypt and decrypt payloads. It uses the jackson-json-crypto library to ensure that sensitive data within workflow inputs and outputs is stored in an encrypted format in the Temporal Server history, rather than plain text.

    When using this pattern, fields in your data models (e.g., a MyCustomer class) will appear in the Temporal Web UI as encrypted objects containing a salt, iv, and value instead of the raw data.

  9. How to use Heartbeats to manage long-running batch Activities

    main

    In Temporal, an Activity can run for an extended period. To prevent the system from assuming the Activity has failed, the Activity must periodically report it is still alive using Heartbeat.

    Key concepts for batch processing with Heartbeats:

    • Heartbeat Timeout: If a Worker is restarted or fails, the Activity is retried only after the configured Heartbeat Timeout expires.
    • Heartbeat Details: Temporal allows you to store data within Heartbeat details. This is critical for batch processing because these details are passed to the next Activity attempt. By storing the current progress (e.g., the last processed record index) in the heartbeat details, you can avoid reprocessing the entire batch from the beginning when a failure occurs.
  10. Use the auto-heartbeating utility for activities with HeartbeatTimeout

    main

    This sample demonstrates an "auto-heartbeating" utility implemented via an interceptor. It is designed for activities that define a HeartbeatTimeout but where explicitly calling the heartbeat API within the activity code is difficult or undesirable.

    Use Cases

    • Long-running activities: When you want to maintain a heartbeat for long tasks without manually injecting heartbeat calls into the business logic.
    • Variable duration activities: When an activity might complete very quickly most of the time, but occasionally takes minutes. This allows you to set a long StartToClose timeout without sending an immediate heartbeat, instead delaying the first heartbeat until the expected "shorter" duration of execution has passed.

    Important Warnings

    • Manual Heartbeating is Preferred: It is generally recommended to heartbeat directly from the activity code.
    • Cancellation Lag: Because the heartbeat is handled by an interceptor, the activity code may continue to run for a period after a cancellation has been handled by the Temporal system.
    • Scale: This sample has not been tested on large-scale workloads; ensure you perform load testing for your specific use case.
    # No runnable code snippet provided in the source for the implementation logic itself, only the execution command.
  11. Understand the Workflow iterator pattern

    main

    The Workflow iterator pattern is used to process large sets of records by breaking them into manageable chunks.

    How it works:

    1. A parent Workflow starts a configured number of Child Workflows in parallel.
    2. Each Child Workflow processes a single record.
    3. Once all children in a batch complete, the parent Workflow calls continue-as-new to start a new iteration of children for the next page of records.

    Trade-offs:

    • Advantage: High simplicity in implementation.
    • Disadvantage: Records are processed in batches; the entire batch must wait for the slowest child workflow to complete before the next batch begins.

    Variation: This pattern can also be implemented using Activities instead of Child Workflows.