Skip to Content
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 if the oplog would otherwise grow unboundedly.
  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. If oplog volume or replay cost is the concern (long-running agents, heartbeats, polling, recurring tasks), do not try to skip persistence; add periodic snapshots instead (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 instead of replaying the whole oplog. Use this whenever the oplog grows unboundedly — long-running agents, high-frequency state changes, heartbeats, polling loops, recurring tasks.

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 on a fixed time interval.

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. If your durable state is unexported (the common case), implement Save/Load on the *state before relying on snapshots.

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)
Long-running agent with heartbeats, polling, or recurring tasksDurable + 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-atomic-block-goFine-grained persistence / idempotency / atomicity controls
golem-recurring-task-goLong-running agents that heartbeat or schedule future work