Skip to main content

protoc-gen-go-temporal

temporal + go + protobuf = ❤️

About

A protoc plugin for generating typed Temporal clients and workers in Go from protobuf schemas. This plugin allows:

  • workflow authors to configure sensible defaults and guardrails
  • simplifies the implementation and testing of Temporal workers
  • and streamlines integration by providing typed client SDKs and a generated CLI application


Features

Generated Client with:

  • methods for executing workflows, queries, signals, and updates
  • methods for cancelling or terminating workflows
  • default client.StartWorkflowOptions and client.UpdateWorkflowWithOptionsRequest
  • dynamic workflow ids, update ids, and search attributes via Bloblang expressions
  • default timeouts, id reuse policies, retry policies, wait policies

Generated Worker resources with:

  • functions for calling activities and local activities from workflows
  • functions for executing child workflows and signalling external workflows
  • default workflow.ActivityOptions, workflow.ChildWorkflowOptions
  • default timeouts, parent cose policies, retry policies

Optional CLI with:

  • commands for executing workflows, synchronously or asynchronously
  • commands for starting workflows with signals, synchronously or asynchronously
  • commands for querying existing workflows
  • commands for sending signals to existing workflows
  • typed flags for conventiently specifying workflow, query, and signal inputs

Generated Cross-Namespace (XNS) helpers: [Experimental]

  • with support for invoking a service's workflows, queries, signals, and updates from workflows in a different temporal namespace

Generated Remote Codec Server helpers

Generated Markdown Documentation

Inspiration

This project was inspired by Chad Retz's awesome github.com/cretz/temporal-sdk-go-advanced and Jacob LeGrone's excellent Replay talk on Temporal @ Datadog

Annotate your protobuf services and methods with Temporal options.

proto/example/v1/example.proto
syntax="proto3";

package example.v1;

import "google/protobuf/empty.proto";
import "temporal/v1/temporal.proto";

service Example {
option (temporal.v1.service) = {
task_queue: "example-v1"
};

// CreateFoo creates a new foo operation
rpc CreateFoo(CreateFooRequest) returns (CreateFooResponse) {
option (temporal.v1.workflow) = {
execution_timeout: { seconds: 3600 }
id: 'create-foo/${! name.slug() }'
id_reuse_policy: WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE
query: { ref: "GetFooProgress" }
signal: { ref: "SetFooProgress", start: true }
update: { ref: "UpdateFooProgress" }
};
}

// GetFooProgress returns the status of a CreateFoo operation
rpc GetFooProgress(google.protobuf.Empty) returns (GetFooProgressResponse) {
option (temporal.v1.query) = {};
}

// Notify sends a notification
rpc Notify(NotifyRequest) returns (google.protobuf.Empty) {
option (temporal.v1.activity) = {
start_to_close_timeout: { seconds: 30 }
retry_policy: {
max_attempts: 3
}
};
}

// SetFooProgress sets the current status of a CreateFoo operation
rpc SetFooProgress(SetFooProgressRequest) returns (google.protobuf.Empty) {
option (temporal.v1.signal) = {};
}

// UpdateFooProgress sets the current status of a CreateFoo operation
rpc UpdateFooProgress(SetFooProgressRequest) returns (GetFooProgressResponse) {
option (temporal.v1.update) = {
id: 'update-progress/${! progress.string() }'
};
}
}

// CreateFooRequest describes the input to a CreateFoo workflow
message CreateFooRequest {
// unique foo name
string name = 1;
}

// SampleWorkflowWithMutexResponse describes the output from a CreateFoo workflow
message CreateFooResponse {
Foo foo = 1;
}

// Foo describes an illustrative foo resource
message Foo {
string name = 1;
Status status = 2;

enum Status {
FOO_STATUS_UNSPECIFIED = 0;
FOO_STATUS_READY = 1;
FOO_STATUS_CREATING = 2;
}
}

// GetFooProgressResponse describes the output from a GetFooProgress query
message GetFooProgressResponse {
float progress = 1;
Foo.Status status = 2;
}

// NotifyRequest describes the input to a Notify activity
message NotifyRequest {
string message = 1;
}

// SetFooProgressRequest describes the input to a SetFooProgress signal
message SetFooProgressRequest {
// value of current workflow progress
float progress = 1;
}