Skip to Content
Next — You're reading the unreleased preview docs. APIs and pages may change before the next release.Switch to the current docs →
How-To GuidesGoConfiguring Agent Durability (Go)

Configuring Agent Durability (Go)

Overview

Durability is a property of the agent definition — it lives on the golem.Spec you pass to golem.DefineAgent. There is no attribute or macro; you set two struct fields:

  • Mode — golem.Durable (the default) or golem.Ephemeral.
  • Snapshot — a golem.SnapshotPolicy, defaulting to golem.SnapshotDisabled.

Nothing in the implementation package changes: handlers are written the same way regardless of mode.

Steps

  1. Decide the mode — durable (default) unless the agent is genuinely stateless.
  2. Set Mode on the golem.Spec in the definition package (omit it for durable).
  3. Add a snapshot policy to reduce recovery replay cost, not oplog writes or storage growth.
  4. Build — run golem build.

Durable Agents (Default)

By default every Golem agent is durable — Mode defaults to golem.Durable, so you never write it explicitly:

  • State persists across invocations, failures, and restarts.
  • Every side effect is recorded in an oplog (operation log).
  • On failure, the agent is transparently recovered by replaying the oplog.
  • No special code needed — durability is automatic.

You cannot opt out of oplog writes for a durable agent — the oplog is how durability works. Do not try to skip persistence to reduce oplog volume. Snapshots reduce recovery replay cost, not oplog writes or storage growth. Use an explicit snapshot policy for recovery (below).

// Package counter is the DEFINITION of a standard durable agent. package counter import "github.com/golemcloud/golem/sdks/go/golem" type ID struct{ Name string } // Mode is omitted, so it defaults to golem.Durable. var Agent = golem.DefineAgent[ID](golem.Spec{ Name: "CounterAgent", Description: "A simple durable counter", }) var ( Increment = Agent.Method[golem.Unit, int64]("increment", golem.Description("Increase the count by one")) Value = Agent.Method[golem.Unit, int64]("value", golem.Description("Return the current value")) )

The implementation is ordinary — the private state is rebuilt by oplog replay on recovery:

package impl import ( "myapp/agents/counter" "github.com/golemcloud/golem/sdks/go/golem" ) type state struct{ count int64 } var agent = counter.Agent.Implement(func(counter.ID) *state { return &state{} }) func init() { agent.Handle(counter.Increment, func(ctx *golem.Context[state], _ golem.Unit) int64 { ctx.State.count++ return ctx.State.count }) agent.Handle(counter.Value, func(ctx *golem.Context[state], _ golem.Unit) int64 { return ctx.State.count }) }

Durable with Periodic Snapshots

Same durability guarantees as the default, but recovery starts from the latest snapshot and replays subsequent oplog entries instead of the whole oplog. This reduces replay cost, not oplog writes or storage growth.

Periodic snapshots run at invocation boundaries or while the agent is idle; they do not interrupt an endless handler on a timer. Split recurring work into bounded invocations if it must reach snapshot points.

For Go, implement a custom golem.Snapshotter as well as setting a policy. Custom recovery supports state restoration and OnRestore after restart. Default JSON recovery and manual snapshot-based component updates have separate runtime limitations. See golem-custom-snapshot-go before enabling snapshots.

Set the Snapshot field on the golem.Spec:

import "time" // Snapshot every 10 invocations. var Agent = golem.DefineAgent[ID](golem.Spec{ Name: "CounterAgent", Snapshot: golem.SnapshotEveryN(10), }) // Or at most once per interval. var HeartbeatAgent = golem.DefineAgent[ID](golem.Spec{ Name: "HeartbeatAgent", Snapshot: golem.SnapshotPeriodic(30 * time.Second), }) // Or let the platform pick the cadence. var PipelineAgent = golem.DefineAgent[ID](golem.Spec{ Name: "PipelineAgent", Snapshot: golem.SnapshotDefault, })

The snapshot policy constructors are:

ConstructorMeaning
golem.SnapshotDisabledThe zero value — the platform never snapshots.
golem.SnapshotDefaultSnapshot at the platform’s default cadence.
golem.SnapshotEveryN(n uint16)Snapshot every n invocations.
golem.SnapshotPeriodic(d time.Duration)Snapshot when due at an invocation boundary or while idle, not inside a running handler.

What gets snapshotted

Go reflection cannot see unexported fields, so the idiomatic private state (e.g. an unexported count) is only captured if the state type implements the golem.Snapshotter interface:

type Snapshotter interface { Save() ([]byte, error) Load([]byte) error }

Without a Snapshotter, the snapshot is the JSON of the state’s exported fields only. Use Save/Load on the *state for recovery even when all fields are exported; default JSON serialization does not remove the recovery limitation described above.

Ephemeral Agents

Use ephemeral mode for stateless, per-invocation agents where persistence is not needed:

  • State is discarded after each invocation completes.
  • No durable state across invocations — lower overhead.
  • Useful for pure functions, request handlers, or adapters.
var Agent = golem.DefineAgent[ID](golem.Spec{ Name: "StatelessHandler", Mode: golem.Ephemeral, })

When to Choose Which

Use CaseMode
Counter, shopping cart, workflow orchestratorDurable (default)
Stateless request processor, transformerEphemeral
Long-running saga or multi-step pipelineDurable (default)
Pure computation, no side effects worth persistingEphemeral
Agent that calls external APIs with at-least-once semanticsDurable (default)
Agent with bounded heartbeat, polling, or recurring invocationsDurable + periodic snapshots
Any durable agent whose oplog grows so large that replay is slowDurable + periodic snapshots

When in doubt, use the default (durable). Ephemeral is an optimization for agents that genuinely don’t need persistence; add periodic snapshots whenever recovery time matters.

Key Constraints

  • Mode and snapshot policy are set on the definition (golem.Spec), not the implementation — the handler code is identical either way.
  • Mode defaults to golem.Durable; only set it to switch to golem.Ephemeral.
  • Snapshot defaults to golem.SnapshotDisabled; snapshots do not change durability guarantees, only recovery time.
  • Read-only methods require a durable agent — marking a method on an Ephemeral agent read-only is a definition error (see golem-mark-read-only-go).
  • Unexported private state is not captured by the default reflective snapshot; implement golem.Snapshotter if you snapshot such an agent.
GuideDescription
golem-add-agent-goDefine the agent and its methods in the first place
golem-mark-read-only-goAdd cacheable, side-effect-free query methods (durable only)
golem-recurring-task-goLong-running agents that heartbeat or schedule future work