Skip to content

v1.0.0

Latest

Choose a tag to compare

@slinkydeveloper slinkydeveloper released this 30 Jun 15:17

Restate Go SDK 1.0

We're pleased to announce the release of Restate Go SDK 1.0 πŸŽ‰

Migration guide

If you're upgrading from 0.x, follow this migration guide, or point your coding agent at it: MIGRATION.md.

Changes to the SDK modules

The SDK is now split into several independently versioned Go modules. In particular:

  • SDK remains github.com/restatedev/sdk-go
  • Testing now needs to be pulled separately using go get github.com/restatedev/sdk-go/testing@v1.0.0, to avoid dependency pollution

We're committing to 1.x semver guarantees for SDK and testing module and submodules, except internal and x submodules.

We keep as experimental modules:

  • Mocks: go get github.com/restatedev/sdk-go/x/mocks@v0.26.0
  • Protoc plugin: go get github.com/restatedev/sdk-go/x/protoc-gen-go-restate@v0.26.0

Revamped error interfaces

We've overhauled the error interfaces used in the SDK APIs to be more explicit and to make them easier to use and evolve:

  • TerminalError completes the invocation (or a Run) with a failure, with optional status code and metadata. You can build terminal errors using restate.ToTerminalError or restate.TerminalErrorf.
  • RetryableError is a non-terminal failure that gets retried (a status code). We will evolve this type in the future to support customizing the retry behavior.

BREAKING: Because TerminalError is now a type, the old TerminalError(...) constructor was
renamed to ToTerminalError:

Context operations such as Get, Run, Call and Wait now return a TerminalError directly instead of a generic error.
This makes the SDK's error-handling model explicit right in the signatures: return a TerminalError for failures that are recorded in the Restate journal, and panic on any other error to let Restate retry.

Randomness uses math/rand/v2

Rand(ctx) now returns a standard-library *math/rand/v2.Rand instead of a custom
interface, so the full stdlib API is available. It's still seeded deterministically (same
sequence on every replay) and must not be used inside Run. UUIDs moved to their own
helper:

id := restate.Rand(ctx).UUID().String()   // 0.x
id := restate.UUID(ctx).String()          // 1.0

// the whole math/rand/v2 surface now works (deterministic, replay-safe):
r := restate.Rand(ctx)
roll := r.IntN(6) + 1

Solidified options

We've cleaned up the option vocabulary across the SDK so it's consistent and easier to evolve:

  • Retry policy options are now a single shared vocabulary: the same builders work for Run/RunAsync/RunVoid and for the invocation retry policy (WithInvocationRetryPolicy), with consistent names and types.
  • Codecs are simplified: a single encoding.Codec is used everywhere (handlers, services, ingress, value operations), set with WithCodec, and input/output codecs can now be configured independently via WithInputCodec/WithOutputCodec.

See MIGRATION.md for the exact renames.

(Preview) Scope and limit key to enable flow control

This release adds the SDK API for flow control, the new Restate 1.7 feature to cap how many invocations run concurrently within a scope, with optional hierarchical limit keys. Use it to bound cost (especially for AI agents, where every concurrent invocation is real model/API spend), shield downstream systems from bursts, and share capacity fairly across tenants.

To use scope and limit keys in service to service communication:

// Route every call made through this client into a named scope.
out, err := restate.Service[Output](ctx, "MyService", "Process",
    restate.WithScope("tenant-123")).
    Request(input)

// Add a hierarchical limit key for finer-grained concurrency limits.
out, err := restate.Service[Output](ctx, "MyService", "Process",
    restate.WithScope("tenant-123")).
    Request(input, restate.WithLimitKey("api-key/user42"))

WithScope works on Service, Object and Workflow clients (and their …Send
variants); WithLimitKey works on both in-context calls and ingress requests/sends.

NOTE: This API is in preview and is not enabled by default. To use it in restate-server 1.7, enable the flow control and protocol v7 experimental features via RESTATE_EXPERIMENTAL_ENABLE_PROTOCOL_V7=true and RESTATE_EXPERIMENTAL_ENABLE_VQUEUES=true (new clusters only). See https://docs.restate.dev/services/flow-control for details.

New Signals API

Signals are a first-class way for one invocation to communicate with another: an
invocation waits on a named signal, and any other handler resolves or rejects it by
referencing the target invocation's ID.

// Inside the waiting invocation β€” block until the signal arrives:
approved, err := restate.Signal[bool](ctx, "approved").Result()

// A SignalFuture can also be combined with others via Context.Select,
// exactly like awakeables, calls and timers.
// Inside another handler β€” resolve or reject by target invocation ID:
restate.ResolveSignal(ctx, targetInvocationID, "approved", true)
restate.RejectSignal(ctx, targetInvocationID, "approved", restate.TerminalErrorf("denied"))

Noteworthy bumps

  • Minimum Go version: 1.24 β†’ 1.25.
  • testcontainers-go removed from the core module. It now lives only in the testing
    module (bumped to v0.43.0 there), so consumers of the SDK no longer inherit Docker and
    its dependency tree.
  • go.opentelemetry.io/otel v1.38.0 β†’ v1.44.0
  • google.golang.org/protobuf v1.36.10 β†’ v1.36.11
  • github.com/invopop/jsonschema v0.13.0 β†’ v0.14.0

What's Changed

New Contributors

Full Changelog: v0.24.0...v1.0.0