temporal

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 9, 2026 License: Apache-2.0 Imports: 35 Imported by: 0

README

Helpers

A collection of Temporal helpers

A thin convenience layer over the Temporal Go SDK, holding the pieces that tend to be rewritten in every service.

Overview

The package provides helpers that are commonly reused across Temporal Go applications:

  • client connection configuration
  • authentication and TLS
  • interceptors and context propagators
  • external storage for large payloads
  • Cobra/Viper CLI integration
  • health and readiness endpoints
  • Prometheus metrics
  • Zerolog integration
  • saga compensation

These helpers build on the Temporal Go SDK rather than replacing it. A connection is described by a list of Option values and produces an ordinary client.Client, and the logging and metrics helpers remain directly compatible with the SDK's logger and metrics handler interfaces. The SDK stays directly usable alongside anything here, and nothing is hidden behind a new abstraction.

Full API documentation is on pkg.go.dev.

Installation

go get github.com/zigflow/helpers

The package is named temporal, so it is usually imported as:

import temporal "github.com/zigflow/helpers"

Connection

NewConnection dials Temporal using only the options supplied. Anything an option does not set keeps the SDK default.

c, err := temporal.NewConnection(
    temporal.WithHostPort("temporal.example.com:7233"),
    temporal.WithNamespace("my-namespace"),
    temporal.WithTLS(true,
        temporal.WithTLSServerName("temporal.example.com"),
    ),
)
if err != nil {
    return fmt.Errorf("error connecting to temporal: %w", err)
}
defer c.Close()

Options are applied in the order they are given, so a later option overwrites an earlier one that sets the same field. An empty host and port falls back to client.DefaultHostPort, and an empty namespace to client.DefaultNamespace.

TLS
  • WithTLS(true, ...) enables TLS and builds the connection's tls.Config from the TLSOption values given to it.
  • WithTLS(false) is a no-op. It does not clear an existing TLS configuration, so a disabled flag cannot accidentally undo TLS configured elsewhere.
  • WithTLS and WithConnectionOptions compose in either order without removing each other's settings. WithConnectionOptions replaces the whole of the connection options, but preserves TLS configured by WithTLS when its own TLS field is nil.

WithTLSServerName overrides the server name (SNI) used to validate the server certificate. It is needed when the endpoint address does not match the certificate hostname, for example behind AWS PrivateLink.

Authentication

  • WithAPICredentials(apiKey) authenticates with a Temporal API key. An empty key is a no-op.
  • WithMTLS(certPath, certKey) authenticates with an mTLS client certificate, loading the key pair from disk when the option is applied. A pair that cannot be loaded is reported as an error from NewConnection.
  • WithAuthDetection(apiKey, certPath, certKey) chooses between them.

WithAuthDetection uses the following precedence, and only ever applies one method:

  1. an API key, when apiKey is supplied
  2. mTLS, when both the certificate and the key are supplied
  3. otherwise no authentication option is applied

Interceptors and context propagators

WithInterceptors sets the interceptors applied to client calls, such as starting a workflow or sending a signal, and WithContextPropagators sets the propagators that carry values between the client, workflows and activities, for example a trace or tenant identifier held in the caller's context.Context.

c, err := temporal.NewConnection(
    temporal.WithInterceptors([]interceptor.ClientInterceptor{
        tracingInterceptor,
    }),
    temporal.WithContextPropagators([]workflow.ContextPropagator{
        tenantPropagator,
    }),
)

Both options replace the whole set rather than adding to it, so a later call overwrites an earlier one - pass everything in a single call. A nil or empty slice leaves nothing configured.

Order within the slice matters:

  • earlier interceptors wrap later ones, so the first one given is the outermost
  • propagators are invoked in the order they are given

An interceptor that also implements interceptor.WorkerInterceptor is used for worker interception as well, wrapping any interceptor set in the worker's own options. The same interceptor should not be given in both places.

Context propagators only carry a value end to end when the same set is configured on every client and worker that takes part, otherwise a value injected at one end is not extracted at the other.

External storage

Payloads too large to send to the Temporal server inline can be offloaded to external storage, leaving only a reference in the workflow history. ExternalConfigS3Factory builds an S3-backed storage driver, and WithExternalStorageFactory attaches it to a connection:

c, err := temporal.NewConnection(
    temporal.WithExternalStorageFactory(temporal.ExternalConfig{
        PayloadSizeThreshold: 1024 * 1024,
        Factory: temporal.ExternalConfigS3Factory(ctx, &temporal.S3Config{
            Bucket: "my-payload-bucket",
            Region: "eu-west-2",
        }),
    }),
)

The factory runs when the option is applied rather than when it is built, so an AWS configuration that cannot be loaded is reported as an error from NewConnection. An ExternalConfig without a Factory is an error too.

Bucket and Region are the only S3Config fields most deployments need. The rest are optional, and only matter for credentials the AWS SDK cannot resolve on its own, for S3-compatible storage, or to override a driver default:

  • AccessKeyID and SecretAccessKey set static credentials. Leave both empty to use the AWS default credential chain, which covers the environment, shared configuration files, and instance or workload identity.
  • SessionToken accompanies temporary credentials. It may only be set alongside both AccessKeyID and SecretAccessKey; on its own, or with only one of them, it is reported as an error.
  • Endpoint points at an S3-compatible service such as MinIO or LocalStack. An empty endpoint uses whichever AWS endpoint the SDK resolves for the region.
  • UsePathStyle addresses the bucket in the request path rather than in the hostname, which S3-compatible services usually require.
  • DriverName names the driver, defaulting to aws.s3driver. Every driver attached to a client needs a unique name, so this is only needed when more than one is registered.
  • MaxPayloadSize is the largest payload the driver accepts, defaulting to 50 MiB. Anything above it is reported as an error rather than stored.

ExternalConfig carries the settings that apply whatever the backend:

  • PayloadSizeThreshold is the serialized payload size, in bytes, at which a payload is offloaded instead of being sent inline. Zero uses the SDK default of 256 KiB.
  • StorageDriverSelector routes each payload to a particular driver, or leaves it inline. When it is nil, the first driver stores every payload over the threshold.

This is experimental, following the status of the underlying SDK support.

Environment configuration

NewConnectionWithEnvvars uses the Temporal SDK environment configuration as its starting point, then applies the supplied options on top, so an option always wins over the environment.

c, err := temporal.NewConnectionWithEnvvars(
    temporal.WithZerolog(&log.Logger),
)

This is experimental, following the status of the underlying SDK support.

Cobra/Viper integration

NewCobraOpts registers the Temporal flags on a command and binds them to a TemporalOpts, which ParseCobraOpts then converts into connection options.

Each flag takes its default from Viper, so values can equally come from a config file or the environment. The API key's default is hidden from the help output so it is never printed to the terminal.

var opts struct {
    temporal *temporal.TemporalOpts
}

cmd := &cobra.Command{
    Use:   "run",
    Short: "Run a Temporal worker",
    RunE: func(cmd *cobra.Command, args []string) error {
        metrics, err := temporal.NewPrometheusHandler(
            opts.temporal.MetricsListenAddress,
            opts.temporal.MetricsPrefix,
            nil,
        )
        if err != nil {
            return fmt.Errorf("error creating prometheus handler: %w", err)
        }
        defer metrics.Close()

        c, err := temporal.NewConnection(
            append(
                temporal.ParseCobraOpts(opts.temporal),
                temporal.WithZerolog(&log.Logger),
                temporal.WithMetrics(metrics),
            )...,
        )
        if err != nil {
            return fmt.Errorf("error connecting to temporal: %w", err)
        }
        defer c.Close()

        w := worker.New(c, TaskQueue, worker.Options{})

        if err := temporal.NewHealthCheck(
            cmd.Context(),
            []string{TaskQueue},
            opts.temporal.HealthListenAddress,
            c,
        ); err != nil {
            return fmt.Errorf("error creating health check: %w", err)
        }

        if err := w.Run(worker.InterruptCh()); err != nil {
            return fmt.Errorf("worker stopped: %w", err)
        }

        return nil
    },
}

opts.temporal = temporal.NewCobraOpts(cmd, &temporal.TemporalOpts{})

ParseCobraOpts covers the client: host and port, namespace, TLS with its server name, and whichever authentication WithAuthDetection selects. Any extra options passed to it are appended, so they are applied last and win over the derived ones. The health and metrics listen addresses are not included, because they configure servers rather than the client, and are wired up separately as above.

Health checks

NewHealthCheck starts an HTTP health server for a worker and serves three endpoints:

Endpoint Checks
/livez Temporal connectivity
/readyz Temporal connectivity and the configured task queues
/health alias of /readyz

Readiness describes both the workflow and the activity task queue for every task queue it was given. A healthy check responds 200 and an unhealthy one 503, both with a JSON body describing what was checked. Each request gets its own two second timeout.

The listener is created synchronously, so an address that cannot be bound is returned as an error and nothing is started:

if err := temporal.NewHealthCheck(ctx, []string{TaskQueue}, "0.0.0.0:3000", c); err != nil {
    return fmt.Errorf("error creating health check: %w", err)
}

The server itself then runs in the background and shuts down when its context is cancelled. Errors raised by the running server after that point are logged rather than returned, so they are not observable through the returned error.

Prometheus

Lifecycle-aware usage

This is the recommended approach. NewPrometheusHandler returns a PrometheusHandler that owns the underlying Tally scope, which the caller closes when it is done with it.

metrics, err := temporal.NewPrometheusHandler(
    "0.0.0.0:9090",
    "my_app",
    nil,
)
if err != nil {
    return err
}
defer metrics.Close()

c, err := temporal.NewConnection(
    temporal.WithMetrics(metrics),
)

Metrics are served on the given address under /metrics, with the prefix prepended to every metric name. An empty address attaches the metrics endpoint to Go's default HTTP mux instead of starting a server of its own, and a nil registry uses the Prometheus default registry.

Convenience usage

WithPrometheusMetrics creates the handler and attaches it to the client in one call:

c, err := temporal.NewConnection(
    temporal.WithPrometheusMetrics("0.0.0.0:9090", "my_app", nil),
)

By design it does not expose the closer, so the metrics reporter cannot be shut down by the caller. That makes it most appropriate when the reporter is expected to live for the lifetime of the process. Use NewPrometheusHandler with WithMetrics whenever lifecycle ownership matters.

Error handling

Both take the same optional onError argument, which decides how the reporter reports its own failures:

  • no handler supplied: failures are logged at fatal level, terminating the process
  • one handler supplied: that handler is called with the error
  • an explicit nil: nil is passed through to Tally, so Tally applies its own default behaviour
  • more than one handler: an error is returned and no handler is created

Reporter failures are not returned by the constructor. A listen address that cannot be bound, for example, is reported asynchronously through onError once the reporter is running.

Logging

Zerolog

NewZerologHandler adapts a Zerolog logger to the SDK's logger interface, and WithZerolog applies one directly to a connection:

c, err := temporal.NewConnection(
    temporal.WithZerolog(&log.Logger),
)

Levels and structured key/value pairs are passed through, and the level configured on the Zerolog logger still applies.

slog

Unlike Zerolog, log/slog needs no adapter from this package. The SDK ships log.NewStructuredLogger in go.temporal.io/sdk/log, which already turns an *slog.Logger into an SDK logger, so it is passed straight to WithLogger:

// pkg/logger/logger.go
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
    Level: slog.LevelDebug,
}))

c, err := temporal.NewConnectionWithEnvvars(
    temporal.WithLogger(log.NewStructuredLogger(logger)),
)

As with Zerolog, levels and structured key/value pairs are passed through, and the level configured on the slog.Handler still applies.

Zap

Zap needs no adapter from this package either. zapslog, from go.uber.org/zap/exp/zapslog, bridges a *zap.Logger's Core into a slog.Handler, and the SDK's own log.NewStructuredLogger takes it from there:

// pkg/logger/logger.go
zapLogger, _ := zap.NewProduction()
handler := zapslog.NewHandler(zapLogger.Core())
logger := log.NewStructuredLogger(slog.New(handler))

c, err := temporal.NewConnectionWithEnvvars(
    temporal.WithLogger(logger),
)

Levels and structured key/value pairs are passed through, and the level configured on the zapcore.Core still applies.

Saga compensation

Compensator is a LIFO stack of compensation functions. Add registers a compensation after its forward step has succeeded, and Compensate runs the registered functions in reverse order.

Pass Compensate the original workflow context. It derives a disconnected context internally, so there is no need to call workflow.NewDisconnectedContext first.

func MyWorkflow(ctx workflow.Context) (err error) {
    var saga temporal.Compensator

    defer func() {
        if err == nil {
            return
        }

        saga.Compensate(ctx)
    }()

    if err = workflow.ExecuteActivity(ctx, CreateOrder).Get(ctx, nil); err != nil {
        return err
    }
    saga.Add(func(ctx workflow.Context) error {
        return workflow.ExecuteActivity(ctx, CancelOrder).Get(ctx, nil)
    })

    if err = workflow.ExecuteActivity(ctx, TakePayment).Get(ctx, nil); err != nil {
        return err
    }
    saga.Add(func(ctx workflow.Context) error {
        return workflow.ExecuteActivity(ctx, RefundPayment).Get(ctx, nil)
    })

    return nil
}

Every registered compensation is attempted even when one fails: the failure is logged through the workflow logger and the next compensation still runs. Compensate returns nothing, so the original workflow error is not replaced.

The disconnected context keeps the parent's configuration, such as activity options, but not its cancellation, so compensations still run for a workflow that is being cancelled. It is cancelled once Compensate returns, so a compensation must complete its work before returning.

Go compatibility

This module requires Go 1.26.0, as declared in go.mod.

The minimum supported Go version follows the minimum supported version of the Temporal Go SDK.

Contributing

Open in a container
Commit style

All commits must be done in the Conventional Commit format.

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

Documentation

Overview

Package temporal provides reusable helpers for building applications with the Temporal Go SDK.

The helpers cover the parts of a Temporal service that tend to be rewritten every time: client connection and TLS configuration, authentication, Cobra and Viper flag wiring, health and readiness endpoints, Prometheus metrics, Zerolog integration and saga compensation.

It is a thin convenience layer, not a framework or an abstraction over Temporal. A connection is described by a list of Option values and produces an ordinary Temporal client, and the logging and metrics helpers remain directly compatible with the SDK's logger and metrics handler interfaces, so the SDK stays directly usable alongside anything here.

Start at NewConnection for the connection options, NewCobraOpts for CLI integration, NewHealthCheck for health endpoints, NewPrometheusHandler for metrics and Compensator for saga compensation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewConnection

func NewConnection(options ...Option) (client.Client, error)

NewConnection creates a Temporal connection from the supplied options only, starting from a zero-valued client.Options. Anything an option does not set keeps the SDK's own default.

func NewConnectionWithEnvvars

func NewConnectionWithEnvvars(options ...Option) (client.Client, error)

NewConnectionWithEnvvars creates a Temporal connection using the Temporal SDK environment configuration as its starting point, then applies options on top, so an option always wins over the environment.

This is experimental.

@link https://docs.temporal.io/develop/environment-configuration#sdk-usage-example-go

func NewHealthCheck

func NewHealthCheck(ctx context.Context, taskQueues []string, address string, c client.Client) error

NewHealthCheck starts an HTTP health server for a Temporal worker and returns once it is listening.

Three endpoints are served on address:

  • /livez reports whether the Temporal service is reachable.
  • /readyz reports Temporal reachability and additionally describes the workflow and activity task queues named in taskQueues.
  • /health is an alias of /readyz.

A healthy check responds 200 and an unhealthy one 503, both with a JSON body describing what was checked. Each request gets its own two second timeout.

The listener is created synchronously, so an address that cannot be bound is returned as an error and nothing is started. The server then runs in the background and shuts down when ctx is cancelled. Errors from the running server, and from that shutdown, are logged rather than returned, so they are not observable through the returned error.

func NewZerologHandler

func NewZerologHandler(zlog *zerolog.Logger) log.Logger

NewZerologHandler adapts a Zerolog logger to the Temporal SDK's logger interface, so client and worker logs join the application's own output. Levels and structured key/value pairs are passed through, and the level configured on zlog still applies.

See WithZerolog to use the result as a client logger.

Types

type Compensator

type Compensator struct {
	// contains filtered or unexported fields
}

Compensator is a LIFO stack of compensation functions for the saga pattern.

Usage pattern:

  1. Declare a Compensator at the top of the workflow function. The zero value is ready to use.
  2. Defer a block that calls Compensator.Compensate when the workflow is failing.
  3. After each forward step succeeds, call Compensator.Add to register its undo.
  4. If the workflow fails or is cancelled, the deferred block calls Compensate with the original workflow context, and the registered functions run in reverse order.

Compensate derives its own disconnected context, so callers never need workflow.NewDisconnectedContext themselves.

func (*Compensator) Add

func (c *Compensator) Add(fn func(workflow.Context) error)

Add registers a compensation function, undoing the forward step that has just succeeded. Registration order is the order steps succeed in, and Compensator.Compensate calls the functions in reverse.

func (*Compensator) Compensate

func (c *Compensator) Compensate(ctx workflow.Context)

Compensate runs every registered compensation in reverse order.

All of them are attempted even when one fails: a failure is logged through the workflow logger and the next compensation still runs. Nothing is returned, so the original workflow error is not replaced.

Pass the original workflow context. Compensate derives a disconnected context from it, which keeps the parent's configuration but not its cancellation, so compensations still run for a workflow that is being cancelled. That context is cancelled once Compensate returns, so a compensation must complete its work before returning.

type ExternalConfig

type ExternalConfig struct {
	Factory               ExternalConfigFactory
	PayloadSizeThreshold  int
	StorageDriverSelector converter.StorageDriverSelector
}

type ExternalConfigFactory

type ExternalConfigFactory func() ([]converter.StorageDriver, error)

func ExternalConfigS3Factory

func ExternalConfigS3Factory(ctx context.Context, cfg *S3Config) ExternalConfigFactory

type Option

type Option func(*client.Options) error

Option configures a client.Options before the connection is dialled. Options are applied in the order they are given, so a later option overwrites an earlier one that sets the same field.

func ParseCobraOpts

func ParseCobraOpts(opts *TemporalOpts, overrides ...Option) []Option

ParseCobraOpts turns parsed TemporalOpts into the connection options for NewConnection: host and port, namespace, TLS with its server name, and whichever authentication WithAuthDetection selects.

Overrides are appended, so they are applied last and win over the derived options.

The health and metrics listen addresses are not included, because they configure servers rather than the client. Wire those up separately with NewHealthCheck and NewPrometheusHandler, as in the example above.

func WithAPICredentials

func WithAPICredentials(apiKey string) Option

WithAPICredentials authenticates with a Temporal API key. An empty apiKey is a no-op, so it leaves any credentials already configured in place.

func WithAuthDetection

func WithAuthDetection(apiKey, certPath, certKey string) Option

WithAuthDetection chooses an authentication method from whichever values are supplied, in precedence order:

  1. an API key, when apiKey is not empty
  2. mTLS, when both certPath and certKey are not empty
  3. otherwise no authentication option is applied, via WithNoOp

Only one method is ever used, and the choice is made when the option is built rather than when it is applied.

func WithConnectionOptions

func WithConnectionOptions(connection *client.ConnectionOptions) Option

WithConnectionOptions replaces the whole of the client's connection options.

TLS is the exception: when connection.TLS is nil, TLS configured by WithTLS is preserved, so the two options compose in either order without silently discarding each other's settings. Set connection.TLS to override that deliberately.

func WithContextPropagators added in v0.1.1

func WithContextPropagators(propagators []workflow.ContextPropagator) Option

WithContextPropagators sets the context propagators used to carry values between the client, workflows and activities, for example a trace or tenant identifier held in the caller's context.Context.

The whole set is replaced rather than added to, so a later call overwrites an earlier one; pass every propagator in a single call. A nil or empty slice leaves no propagators configured.

Propagators run in the order they are given, and the same set must be given to every client and worker that takes part, otherwise a value injected at one end is not extracted at the other.

func WithCredentials

func WithCredentials(credential client.Credentials) Option

WithCredentials sets the credentials used to authenticate with Temporal. WithAPICredentials, WithMTLS and WithAuthDetection are usually more convenient.

func WithDataAndFailureConverter

func WithDataAndFailureConverter(cvt converter.DataConverter) Option

WithDataAndFailureConverter applies cvt as both the data converter and, via WithFailureConverter, the failure converter. This is normally what an encrypting or compressing converter wants, so that failure detail is covered as well as payloads.

func WithDataConverter

func WithDataConverter(cvt converter.DataConverter) Option

WithDataConverter sets the converter used for workflow and activity payloads. It does not affect failures; see WithDataAndFailureConverter.

func WithExternalStorage

func WithExternalStorage(st converter.ExternalStorage) Option

WithExternalStorage sets the external storage used for payloads too large to send to the Temporal server inline.

func WithExternalStorageFactory

func WithExternalStorageFactory(e ExternalConfig) Option

WithExternalStorageFactory sets the external storage from an ExternalConfig by invoking e.Factory and handing the drivers it returns to WithExternalStorage, together with e.StorageDriverSelector and e.PayloadSizeThreshold.

The factory runs when the option is applied rather than when it is built, so building an option never talks to the storage backend. An ExternalConfig without a Factory is an error, and so is a factory that fails; a failing factory's error is wrapped rather than returned as it is, so the cause is still reachable with errors.Is and errors.As.

func WithFailureConverter

func WithFailureConverter(cvt converter.DataConverter) Option

WithFailureConverter sets a failure converter that encodes failures with cvt. Common failure attributes, such as the message and stack trace, are encoded too, so a converter that encrypts payloads also covers failure detail.

func WithHostPort

func WithHostPort(hostPort string) Option

WithHostPort sets the address of the Temporal frontend. An empty hostPort falls back to the SDK default of client.DefaultHostPort.

func WithInterceptors added in v0.1.1

func WithInterceptors(interceptors []interceptor.ClientInterceptor) Option

WithInterceptors sets the interceptors applied to client calls, such as starting a workflow or sending a signal.

Earlier interceptors wrap later ones, so the first one given is the outermost. The whole set is replaced rather than added to, so a later call overwrites an earlier one; pass every interceptor in a single call. A nil or empty slice leaves no interceptors configured.

An interceptor that also implements interceptor.WorkerInterceptor is used for worker interception as well, wrapping any interceptor set in the worker's own options. The same interceptor should not be given in both places.

func WithLogger

func WithLogger(logger log.Logger) Option

WithLogger sets the logger used by the client, and by any worker created from it. Use WithZerolog to pass an existing Zerolog logger.

func WithMTLS

func WithMTLS(certPath, certKey string) Option

WithMTLS authenticates with an mTLS client certificate, loading the key pair from disk when the option is applied. A pair that cannot be loaded, or whose key does not match its certificate, is reported as an error from the connection constructor.

The SDK applies the certificate to the connection's TLS configuration when the client is dialled, creating one if none is set, so TLS is in use without also calling WithTLS. Use WithTLS when the TLS configuration itself needs customising, for example with WithTLSServerName.

func WithMetrics

func WithMetrics(metrics client.MetricsHandler) Option

WithMetrics sets the client's metrics handler. Pass the handler returned by NewPrometheusHandler when the caller needs to close it; WithPrometheusMetrics is the shorter option when it does not.

func WithNamespace

func WithNamespace(namespace string) Option

WithNamespace sets the Temporal namespace. An empty namespace falls back to the SDK default of client.DefaultNamespace.

func WithNoOp

func WithNoOp() Option

WithNoOp does nothing. It is useful where an Option has to be returned but there is nothing to configure, as WithAuthDetection does when no credentials are supplied.

func WithPrometheusMetrics

func WithPrometheusMetrics(listenAddress, prefix string, registry *prom.Registry, onError ...func(error)) Option

WithPrometheusMetrics

Convenience helper that creates a Prometheus metrics handler and attaches it to the client options in a single call.

By design, this does not expose the closer, so the metrics handler cannot be shut down by the caller - that is the trade-off for the shorter call site. If you need lifecycle control, create the handler yourself with NewPrometheusHandler, defer its Close method, and pass it to WithMetrics:

metrics, err := temporal.NewPrometheusHandler(
	opts.temporal.MetricsListenAddress,
	opts.temporal.MetricsPrefix,
	nil,
)
if err != nil {
	return err
}
defer metrics.Close()

c, err := temporal.NewConnection(
	temporal.WithMetrics(metrics),
)

func WithTLS

func WithTLS(enabled bool, tlsOpts ...TLSOption) Option

WithTLS enables TLS and builds the connection's tls.Config from tlsOpts.

When enabled is false the option is a no-op: it does not clear TLS configuration set elsewhere, so a disabled flag cannot accidentally undo mTLS credentials or WithConnectionOptions.

func WithZerolog

func WithZerolog(logger *zerolog.Logger) Option

WithZerolog uses an existing Zerolog logger as the client logger. It is shorthand for WithLogger with NewZerologHandler.

type PrometheusHandler

type PrometheusHandler struct {
	client.MetricsHandler
	// contains filtered or unexported fields
}

PrometheusHandler is a Temporal metrics handler backed by a Prometheus reporter.

It embeds the SDK's metrics handler interface, so it can be passed straight to WithMetrics, and it owns the underlying Tally scope. The caller owns the handler, and is responsible for calling PrometheusHandler.Close.

func NewPrometheusHandler

func NewPrometheusHandler(
	listenAddress,
	prefix string,
	registry *prom.Registry,
	onError ...func(error),
) (*PrometheusHandler, error)

NewPrometheusHandler creates a Prometheus-backed metrics handler for a Temporal client. The caller owns it and should call PrometheusHandler.Close when it is no longer needed, usually with defer.

Metrics are served on listenAddress under /metrics, with prefix prepended to every metric name. An empty listenAddress attaches the metrics endpoint to Go's default HTTP mux instead of starting a server of its own. A nil registry uses the Prometheus default registry. Timers are reported as histograms.

The optional onError argument decides how the reporter reports its own failures:

  • not supplied: failures are logged at fatal level, terminating the process
  • one function: that function is called with the error
  • explicitly nil: nil is passed through to Tally, so Tally's own default behaviour applies
  • more than one: an error is returned and no handler is created

Reporter failures are not returned from here. A listen address that cannot be bound, for example, is reported asynchronously through onError once the reporter is running.

func (*PrometheusHandler) Close

func (h *PrometheusHandler) Close() error

Close flushes and releases the underlying Tally scope, and reports whatever the scope reports. A handler with no scope to release, such as the zero value, closes without error.

type S3Config

type S3Config struct {
	Bucket string
	Region string

	// These are all optional - ignored if empty
	DriverName      string
	MaxPayloadSize  int
	Endpoint        string
	AccessKeyID     string
	SecretAccessKey string
	SessionToken    string
	UsePathStyle    bool
}

type TLSOption

type TLSOption func(*tls.Config) error

TLSOption configures the tls.Config built by WithTLS. TLS options are applied in order, and only when TLS is enabled.

func WithTLSServerName

func WithTLSServerName(serverName string) TLSOption

WithTLSServerName overrides the TLS server name (SNI) used to validate the server certificate. It is needed when the endpoint address does not match the certificate hostname, for example behind AWS PrivateLink. An empty serverName is a no-op.

type TemporalOpts

type TemporalOpts struct {
	Address              string
	APIKey               string
	HealthListenAddress  string
	MetricsListenAddress string
	MetricsPrefix        string
	MTLSCertPath         string
	MTLSKeyPath          string
	Namespace            string
	ServerName           string
	TLSEnabled           bool
}

TemporalOpts holds the values behind the flags registered by NewCobraOpts. Declare one, or embed it in a command's own options struct, and pass a pointer to NewCobraOpts.

func NewCobraOpts

func NewCobraOpts(cmd *cobra.Command, opts *TemporalOpts) *TemporalOpts

NewCobraOpts registers the Temporal flags on cmd, binding each one to a field of opts, and returns opts for convenience.

Every flag takes its default from Viper, so a value can equally come from a config file or the environment. The keys are health_listen_address, metrics_listen_address, metrics_prefix, temporal_address, temporal_api_key, temporal_tls_client_cert_path, temporal_tls_client_key_path, temporal_namespace, temporal_server_name and temporal_tls. The two listen addresses, the address and the namespace have defaults; the rest default to empty.

The API key's default is hidden from the help output, so a key already in the configuration is not printed to the terminal.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL