protoc-gen-go-temporal

repository·main·Indexed 41 days ago

https://github.com/cludden/protoc-gen-go-temporal

A protoc plugin that automates the generation of typed Temporal client and worker code in Go from protobuf definitions, reducing boilerplate and enforcing best practices.

Tokens
107.7K
Snippets
285
Records
443
Agent score
49%

What's inside protoc-gen-go-temporal

  1. Overview of protoc-gen-go-temporal

    main

    protoc-gen-go-temporal is a protoc plugin designed to generate typed Temporal clients and workers in Go directly from protobuf schemas.

    It is used to:

    • Configure sensible defaults and guardrails for workflow authors.
    • Simplify the implementation and testing of Temporal workers.
    • Streamline integration by providing typed client SDKs and a generated CLI application.
  2. Generated helpers and extensions

    main

    Beyond the core Client and Worker, the plugin can generate several specialized helpers:

    • Nexus Helpers [Experimental]: Support for invoking a service's workflows via Nexus operations.
    • Cross-Namespace (XNS) Helpers: Support for invoking workflows, queries, signals, and updates from workflows residing in a different Temporal namespace or cluster.
    • Remote Codec Server Helpers: Support for remote codec server integration.
    • Markdown Documentation: Automatically generated documentation.
  3. What is Cross-Namespace (XNS) functionality?

    main
    Cross-Namespace (XNS) functionality allows workflows in one Temporal namespace or cluster to interact with workflows in a different namespace or cluster. This includes invoking workflows, sending signals, executing queries, and performing updates. The protoc-gen-go-temporal plugin facilitates this by generating type-safe helper functions that wrap these cross-namespace operations as activities.
  4. Overview of generated Temporal service structures

    main

    The protoc-gen-go-temporal plugin generates Go code that maps Protobuf service definitions to Temporal primitives. The generated documentation organizes these mappings into several key categories:

    • Workflows: Protobuf methods mapped to Temporal Workflows.
    • Activities: Protobuf methods mapped to Temporal Activities.
    • Queries: Protobuf methods mapped to Temporal Queries (read-only state access).
    • Signals: Protobuf methods mapped to Temporal Signals (asynchronous input to a running workflow).
    • Updates: Protobuf methods mapped to Temporal Updates (asynchronous input with a response).
    • Messages: Protobuf message types used as inputs and outputs for the above primitives.

    This structure allows developers to define their Temporal orchestration logic using standard Protobuf service definitions, which are then compiled into type-safe Go interfaces for interacting with the Temporal cluster.

  5. Features of the generated CLI

    main

    The plugin can optionally generate a CLI application for interacting with your workflows:

    • Workflow Execution: Commands to execute workflows either synchronously or asynchronously.
    • Workflow Signaling: Commands to start workflows with signals (sync/async).
    • Queries: Commands to query existing workflows.
    • Signals: Commands to send signals to existing workflows.
    • Typed Flags: Conveniently specify workflow, query, and signal inputs using typed flags.
  6. Start XNS Workflows with Signals or Updates

    main

    For atomic initialization, you can start remote workflows with an initial signal or update. This ensures the remote workflow begins its lifecycle with the necessary state already present.

    // Signal with Start
    run, err := examplev1xns.CreateFooWithSetFooProgressAsync(ctx,
        &examplev1.CreateFooRequest{Name: "signal-start-foo"},
        &examplev1.SetFooProgressRequest{Progress: 0.25},
    )
    
    // Update with Start
    updateResult, run, err := examplev1xns.CreateFooWithUpdateFooProgress(ctx,
        &examplev1.CreateFooRequest{Name: "update-start-foo"},
        &examplev1.SetFooProgressRequest{Progress: 0.5},
    )
  7. Interact with asynchronous activities using <Activity>Future

    main

    For every Activity defined in your Protobuf service, the generator produces a corresponding <Activity>Future struct. This struct wraps the underlying workflow.Future from the Temporal Go SDK and provides convenient methods for interacting with asynchronous activity executions. All asynchronous activity helpers (e.g., BarAsync) return this type.

    // Example of an asynchronous activity helper returning a Future
    barF, err := examplev1.BarAsync(ctx, &examplev1.BarInput{})
  8. Use google.protobuf.Duration for time spans

    main

    A Duration represents a signed, fixed-length span of time using seconds and nanos (nanosecond resolution). It is independent of calendars and is used to represent the difference between two Timestamp values.

    JSON Mapping: In JSON, Duration is encoded as a string with an s suffix (e.g., "3s" or "3.000000001s").

  9. Features of protoc-gen-go-temporal

    main

    The plugin generates several key components:

    Generated Client

    Provides methods for:

    • Executing workflows, queries, signals, and updates.
    • Cancelling or terminating workflows.
    • Using default client.StartWorkflowOptions, client.UpdateWorkflowWithOptionsRequest, and more.
    • Dynamic workflow IDs, update IDs, and search attributes via Bloblang expressions.
    • Default timeouts, ID reuse policies, retry policies, and wait policies.

    Generated Worker Resources

    Provides functions for:

    • Calling activities and local activities from workflows.
    • Executing child workflows and signaling external workflows.
    • Using default workflow.ActivityOptions, workflow.ChildWorkflowOptions, timeouts, parent close policies, and retry policies.

    Optional CLI

    Provides commands for:

    • Executing workflows (synchronously or asynchronously).
    • Starting workflows with signals or updates (synchronously or asynchronously).
    • Querying existing workflows.
    • Signaling or updating existing workflows.
    • Typed flags for specifying workflow, query, and signal inputs.

    Other Generated Helpers

    • Nexus helpers [Experimental]: Support for invoking a service's workflows via Nexus operations.
    • Cross-Namespace (XNS) helpers: Support for invoking workflows, queries, signals, and updates from workflows in a different Temporal namespace or cluster.
    • Remote Codec Server helpers.
    • Markdown Documentation.
  10. Start a workflow with an initial update (Update-with-Start)

    main

    :::warning Update-with-start is considered experimental. :::

    Update-with-start allows you to start a workflow and immediately apply an update atomically. This ensures the workflow starts with the desired state modification already applied.

    To enable this, configure the Protobuf service definition using the (temporal.v1.workflow).update.start option. In Go, the generated client provides a method (e.g., CreateFooWithUpdateFooProgress) that returns both the result of the initial update and a handle to the workflow run.

    // Protobuf configuration
    service Example {
      rpc CreateFoo(CreateFooRequest) returns (CreateFooResponse) {
        option (temporal.v1.workflow) = {
          update: { ref: "UpdateFooProgress", start: true }
        };
      }
    
      rpc UpdateFooProgress(SetFooProgressRequest) returns (GetFooProgressResponse) {
        option (temporal.v1.update) = {};
      }
    }
    // Go usage
    updateResult, workflowRun, err := client.CreateFooWithUpdateFooProgress(ctx,
        &examplev1.CreateFooRequest{Name: "test"},
        &examplev1.SetFooProgressRequest{Progress: 50.0},
    )
    
    // Access workflow run
    finalResult, err := workflowRun.Get(ctx)
  11. Advanced Workflow Patterns in Shopping Cart Example

    main

    The Shopping Cart example demonstrates several advanced Temporal patterns implemented via the generated code:

    • Stateful Workflows: Maintains internal state (e.g., a map of item quantities) that persists across multiple interactions.
    • Queries: Uses the Describe query to allow external inspection of the workflow's current state without modifying it.
    • Signals: Uses the Checkout signal to trigger specific workflow transitions (like completion) asynchronously.
    • Updates with Validation: Uses the UpdateCart pattern to modify state with built-in validation logic (e.g., preventing the removal of items that aren't in the cart).
    • Cross-Namespace Activities: Demonstrates how to use 'update-with-start' patterns to initiate workflows across different namespaces.
    • Continue-as-New: Implements logic to monitor for ContinueAsNew suggestions to prevent workflow history from exceeding size limits in long-running sessions.
  12. Use generated test clients for Temporal workflows

    main

    The plugin generates a TestClient that mirrors your production client interface but is designed to work within Temporal's testsuite.TestWorkflowEnvironment. This client allows you to interact with workflows, signals, queries, and updates in a deterministic test environment.

    To initialize a test client, use the generated constructor (e.g., NewTestExampleClient) which requires:

    1. A *testsuite.TestWorkflowEnvironment.
    2. An implementation of your workflows.
    3. An implementation of your activities.
    // Constructor for test client
    func NewTestExampleClient(
        env *testsuite.TestWorkflowEnvironment, 
        workflows ExampleWorkflows, 
        activities ExampleActivities,
    ) *TestExampleClient
    
    // The client provides the same methods as the production client:
    // - Workflow execution: CreateFoo, CreateFooAsync, GetCreateFoo
    // - Signals: SetFooProgress
    // - Queries: GetFooProgress
    // - Updates: UpdateFooProgress