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 GuidesScalaCreating Ephemeral (Stateless) Agents (Scala)

Creating Ephemeral (Stateless) Agents (Scala)

Overview

An ephemeral agent is a Golem agent that gets a fresh instance for every invocation. Unlike the default durable agents, ephemeral agents:

  • No shared state: Each invocation starts from a fresh constructor call — field values set in one call are gone by the next
  • No method recovery: An oplog is recorded lazily for inspection. If the executor restarts while preparing an invocation, Golem can replay the recorded initialization so that the method can still start. Once the method starts, a failure is terminal; Golem does not replay the method.
  • No persistence: The agent’s memory is discarded after each invocation completes
  • Logical identity: Constructor parameters address a logical target; each invocation receives a final per-call ephemeral identity.

This makes ephemeral agents ideal for pure request handlers, stateless transformers, adapters, and serverless-style functions where each call is independent.

How to Create an Ephemeral Agent

Pass mode = DurabilityMode.Ephemeral to the @agentDefinition annotation:

import golem.runtime.annotations.{agentDefinition, agentImplementation, DurabilityMode} import golem.BaseAgent import scala.concurrent.Future @agentDefinition(mode = DurabilityMode.Ephemeral) trait RequestHandler extends BaseAgent { class Id() def handle(input: String): Future[String] } @agentImplementation() final class RequestHandlerImpl extends RequestHandler { override def handle(input: String): Future[String] = Future.successful(s"processed: $input") }

What “Fresh Instance Per Invocation” Means

Consider a durable agent vs an ephemeral one:

// DURABLE (default) — state accumulates across calls @agentDefinition() trait DurableCounter extends BaseAgent { class Id(val name: String) def increment(): Future[Int] } @agentImplementation() final class DurableCounterImpl(name: String) extends DurableCounter { private var count: Int = 0 override def increment(): Future[Int] = Future.successful { count += 1 count } } // Call increment() three times → returns 1, 2, 3 // EPHEMERAL — state resets every call @agentDefinition(mode = DurabilityMode.Ephemeral) trait EphemeralCounter extends BaseAgent { class Id(val name: String) def increment(): Future[Int] } @agentImplementation() final class EphemeralCounterImpl(name: String) extends EphemeralCounter { private var count: Int = 0 override def increment(): Future[Int] = Future.successful { count += 1 count } } // Call increment() three times → returns 1, 1, 1

Each invocation of an ephemeral agent:

  1. Creates a fresh instance via the constructor
  2. Executes the method
  3. Discards the instance entirely

Combining with HTTP Endpoints

Ephemeral agents are a natural fit for HTTP request handlers:

import golem.runtime.annotations._ import golem.BaseAgent import scala.concurrent.Future @agentDefinition(mode = DurabilityMode.Ephemeral, mount = "/api/convert/{name}") trait ConverterAgent extends BaseAgent { class Id(val name: String) @endpoint(method = "POST", path = "/to-upper") def toUpper(input: String): Future[String] @endpoint(method = "POST", path = "/to-lower") def toLower(input: String): Future[String] } @agentImplementation() final class ConverterAgentImpl(private val name: String) extends ConverterAgent { override def toUpper(input: String): Future[String] = Future.successful(input.toUpperCase) override def toLower(input: String): Future[String] = Future.successful(input.toLowerCase) }

When to Use Ephemeral Agents

Both POST endpoints expect a structured JSON body such as {"input":"Hello"}, not a bare string.

Use CaseWhy Ephemeral?
Stateless HTTP API (REST adapter, proxy)No state to persist between requests
Data transformation / format conversionPure function — input in, output out
Validation serviceEach validation is independent
Webhook receiver that forwards eventsNo need to remember previous webhooks
Stateless computation (math, encoding)No side effects worth persisting

When NOT to Use Ephemeral Agents

  • Counters, accumulators, shopping carts — need state across calls → use durable (default)
  • Workflow orchestrators, sagas — need oplog for recovery → use durable (default)
  • Agents calling external APIs where at-least-once semantics matter → use durable (default)
  • Any agent where one call’s result depends on a previous call → use durable (default)

Key Points

  • Ephemeral mode is set at the agent type level — all instances of the type are ephemeral
  • Constructor parameters still define identity — you can have multiple ephemeral agents with different parameters
  • Ephemeral agents can call other agents and make HTTP requests, but do not support every durable API. Promise waits and sleeps are bounded by the configured maximum sleep; ephemeral methods cannot actively suspend for durable recovery.
  • The oplog is recorded lazily for inspection. If the executor restarts while preparing an invocation, Golem can replay the recorded initialization so that the method can still start. Once the method starts, a failure is terminal; Golem does not replay the method.