Temporal Go SDK Samples

repository·main·Indexed 20 days ago

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

A collection of sample Workflow applications written in Go to demonstrate the capabilities of the Temporal Server using the Temporal Go SDK. Examples include the Sliding Window Batch pattern, handling out-of-order signals with AwaitWithTimeout, parallel activities, child workflows with Continue-As-New, cron workflows, and the implementation of a remote Codec Server for payload encoding and decoding.

Tokens
157.9K
Snippets
391
Records
474
Agent score
72%

What's inside samples-go

  1. Overview of the openNclosed fixture

    main
    The openNclosed fixture is designed to start a specific number of Temporal workflows to test different lifecycle states. It can be configured to either keep workflows open for 10 minutes or have them close immediately using the KeepOpen flag. This fixture is primarily used for testing purposes, such as in the Temporal Web pull request #315.
  2. Use the largepayload fixture for Web UI performance testing

    main

    The largepayload fixture is designed to test the performance of the Temporal Web UI by simulating workflows that handle large data payloads. It starts a configurable number of workflows (NumberOfWorkflows), each carrying a 1MB payload (PayloadSize).

    These large payloads are injected into three specific areas:

    1. Memo: Workflow memo data.
    2. Activity Input: Data passed as input to an activity.
    3. Activity Result: Data returned by an activity.

    Use this fixture when you need to evaluate how the Temporal Web UI handles large amounts of data during workflow execution and history inspection.

  3. Google ADK Scenario Samples

    main

    The googleadk directory contains several specialized implementation patterns:

    • Basic agent: A single agent answering questions by calling a tool (e.g., get_weather) implemented via googleadk.ActivityAsTool.
    • multiagent: A coordinator agent that uses ADK's in-workflow transfer_to_agent to delegate tasks to specialist weather and jokes SubAgents.
    • humanintheloop: An agent using a sensitive tool (e.g., delete_resource) where the workflow durably waits on a Temporal signal for human approval before proceeding.
    • chat: A long-lived, signal-driven conversation that uses the continue-as-new pattern (exporting/importing the session) to keep conversation history bounded.
  4. Run a Temporal Worker in AWS Lambda using lambdaworker

    main

    This sample demonstrates how to implement a Temporal Worker inside an AWS Lambda function using the lambdaworker contrib package. This pattern allows for serverless worker deployments. The sample includes optional OpenTelemetry instrumentation that exports traces and metrics through AWS Distro for OpenTelemetry (ADOT).

    Key Components

    • main.go: The Lambda worker entry point. It configures the worker, registers Workflows and Activities, and starts the Lambda handler.
    • greeting/workflow.go: A sample Workflow implementation.
    • greeting/activity.go: A sample Activity implementation.
    • starter/main.go: A helper program to trigger Workflow executions against the Lambda worker.
    • temporal.toml: Configuration for the Temporal client connection.
    • deploy-lambda.sh: Script to build, bundle, and deploy the Lambda function.
    • mk-iam-role.sh: Script to create the IAM role required for Temporal Cloud to invoke the Lambda.
  5. Best practices for polling in Temporal

    main

    This sample collection demonstrates three distinct architectural patterns for implementing polling logic within Temporal workflows, based on community best practices. Depending on your requirements, you should choose one of the following approaches:

    1. Frequently Polling Activity: Use this pattern when an activity needs to check a status or resource very often.
    2. Infrequently Polling Activity: Use this pattern when polling intervals are long or less frequent.
    3. Periodic Polling of a sequence of activities: Use this pattern when you need to poll and then execute a series of activities in a loop.

    Detailed implementation details for each pattern can be found in their respective subdirectories.

  6. What is Temporal Nexus

    main
    Temporal Nexus is a feature designed to connect durable executions across team, namespace, region, and cloud boundaries. It allows teams to share capabilities via well-defined service API contracts that abstract underlying Temporal primitives (like Workflows) or execute arbitrary code. This enables a modular architecture where one team's service can be called by another team's workflow across boundaries.
  7. What is Eager Workflow Start (EWS)?

    main

    Eager Workflow Start (EWS) is an experimental latency optimization designed to reduce the time required to start a workflow.

    When the workflow starter and the worker are collocated (running in the same process) and are aware of each other, they can interact directly, bypassing the Temporal server to save time on several operations.

  8. Use Schedules instead of Cron Jobs

    main
    When implementing recurring workflows in Temporal, it is recommended to use Schedules instead of Cron Jobs. Schedules provide a superior developer experience, offering more configuration options and the ability to update or pause running Schedules without recreating them.
  9. How human-in-the-loop durable approval works with Google ADK

    main

    A human-in-the-loop pattern allows a Google ADK agent to pause execution when a sensitive tool (e.g., delete_resource) is called, waiting for an external human decision. This process is durable because the wait is managed by a Temporal workflow that can survive worker restarts.

    The Workflow Lifecycle:

    1. Tool Invocation: The model calls a tool. The tool checks ctx.ToolConfirmation(). If it is nil, the tool calls ctx.RequestConfirmation("Prompt text", nil) and returns without performing the action. This causes the ADK agent to pause.
    2. Durable Blocking: An ApprovalWorkflow detects the pause using googleadk.PendingConfirmations. It then blocks on a Temporal signal named googleadk.ConfirmationSignalName. This signal must carry a googleadk.ConfirmationDecision.
    3. Resumption: Once the signal is received (via workflow.GetSignalChannel), the workflow calls googleadk.ConfirmationResponse(decision). ADK re-dispatches the original tool call. On this second pass, ctx.ToolConfirmation() will no longer be nil, allowing the tool to proceed or block based on the decision.

    Best Practice: Handle only one pending confirmation per resume pass. Resuming multiple decisions in a single pass can lead to non-replay-stable tool dispatch orders. Instead, answer one decision per Run pass; any remaining pending confirmations will surface again on the subsequent pass.

  10. How to handle out-of-order signals using AwaitWithTimeout

    main

    When a workflow needs to process multiple signals that may arrive out of order, or requires specific timeout logic between signal arrivals, using a workflow.Selector with multiple AddReceive callbacks can become complex and difficult to maintain.

    An alternative pattern is to:

    1. Use separate goroutines to receive signals.
    2. Update shared variables within the workflow with the signal data.
    3. Use workflow.AwaitWithTimeout in the main workflow logic to wait for specific conditions composed of those shared variables.

    This approach keeps the business logic clear and separates signal reception from the workflow's state machine transitions.

    // Pattern overview:
    // 1. Receive signals in separate goroutines to update shared state
    // 2. Use AwaitWithTimeout to progress business logic
    
    // Example of the 'naive' (Selector-based) approach that can become convoluted:
    for {
    	selector := workflow.NewSelector(ctx)
    	selector.AddReceive(workflow.GetSignalChannel(ctx, "Signal1"), func(c workflow.ReceiveChannel, more bool) {
    		// Process signal1
    	})
    	selector.AddReceive(workflow.GetSignalChannel(ctx, "Signal2"), func(c workflow.ReceiveChannel, more bool) {
    		// Process signal2
    	})
    	selector.AddReceive(workflow.GetSignalChannel(ctx, "Signal3"), func(c workflow.ReceiveChannel, more bool) {
    		// Process signal3
    	})
    	cCtx, cancel := workflow.WithCancel(ctx)
    	timer := workflow.NewTimer(cCtx, timeToNextSignal)
    	selector.AddFuture(timer, func(f workflow.Future) {
    		// Process timeout
    	})
    	selector.Select(ctx)
    	cancel()
    	// break out of the loop on certain condition
    }
  11. Understand Child Workflow Continue-As-New visibility

    main

    When a Child Workflow uses the Continue-As-New operation, its subsequent executions are not visible to the Parent Workflow. The Parent Workflow only receives a notification that the Child Workflow has completed once the entire chain of executions (the full execution) has finished, failed, or timed out.

    This pattern is highly effective for processing large datasets. A Child Workflow can iterate through a dataset and call Continue-As-New periodically. This prevents the Parent Workflow's history from being polluted by the granular details of the child's iterative processing.