Record Class AgentState
- Record Components:
agentId- unique identifier for the agent, must not be nullagentName- human-readable display name, may be nullagentType- logical type/category of the agent (e.g., "processor", "monitor"), defaults to "unknown" if nullstatus- current operational status, defaults to UNKNOWN if nulldata- application-specific state data with Object values, never null (empty map if not provided)metadata- system/technical metadata with String values, never null (empty map if not provided)version- optimistic locking version number, incremented on each savesavedAt- timestamp when this state was persisted, defaults to current time if null
This record contains all information necessary to restore an agent to its previous state after a restart, failure, or migration. It serves as the primary data structure for agent persistence operations.
State Components:
| Component | Purpose | Example |
|---|---|---|
| Identity (agentId, agentName, agentType) | Identify the agent | id: "order-proc-1", name: "Order Processor" |
| Status | Current operational state | RUNNING, IDLE, ERROR |
| Data | Business state (flexible Map) | orders processed, current order, counters |
| Metadata | Technical state (String-only) | configuration, timestamps, flags |
| Version | Optimistic concurrency control | Incremented on each save |
| Timestamp (savedAt) | When state was persisted | Used for audit and debugging |
Data vs Metadata:
- data: Business state with any Object values (String, Integer, List, custom POJOs, etc.). This is the primary application state that agents need to preserve.
- metadata: Technical/system state with String values only. Used for configuration, feature flags, timestamps, etc.
Versioning:
The version field enables optimistic locking to prevent lost updates
when multiple processes try to save state concurrently:
// Load current state
AgentState current = persistence.load("agent-1").join();
// Modify state
AgentState modified = AgentState.builder(current.agentId())
.data(current.data())
.data("counter", current.getData("counter", Integer.class) + 1)
.version(current.version() + 1) // Increment version
.build();
// Save - will fail if another process saved in the meantime
try {
persistence.save(modified).join();
} catch (ConcurrentModificationException e) {
// Retry with fresh state
}
Serialization: This record is designed to be easily serializable to various formats:
- JSON - Via Jackson annotations (default)
- Binary - Via Java serialization (Serializable)
- Database - Map to columns/documents
Immutability:
All collections (data, metadata) are defensively copied
to ensure immutability. Use the builder pattern to create modified copies.
Example Usage:
// Create initial state
AgentState state = AgentState.builder("order-processor-1")
.agentName("Order Processor #1")
.agentType("processor")
.status(AgentStatus.RUNNING)
.data("ordersProcessed", 0)
.data("currentBatch", List.of())
.metadata("startTime", Instant.now().toString())
.metadata("environment", "production")
.build();
// Save state
persistenceService.save(state).join();
// Later, load and update state
AgentState loaded = persistenceService.load("order-processor-1").join();
int processed = loaded.getData("ordersProcessed", Integer.class);
AgentState updated = AgentState.builder(loaded.agentId())
.agentName(loaded.agentName())
.agentType(loaded.agentType())
.status(loaded.status())
.data(loaded.data()) // Copy existing data
.data("ordersProcessed", processed + 10) // Update counter
.metadata(loaded.metadata()) // Copy existing metadata
.version(loaded.version() + 1) // Increment version
.build();
persistenceService.save(updated).join();
Recovery Pattern:
// On agent startup, restore previous state
public class OrderProcessorAgent extends BaseAgent implements Stateful {
@Override
public CompletableFuture<Void> start() {
return persistenceService.load(getAgentId())
.thenCompose(state -> {
if (state != null) {
restoreState(state);
log.info("Restored state from {}", state.savedAt());
}
return super.start();
});
}
private void restoreState(AgentState state) {
this.ordersProcessed = state.getData("ordersProcessed", Integer.class);
this.currentBatch = state.getData("currentBatch", List.class);
// Restore other fields...
}
}
- Since:
- 0.1.0
- See Also:
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classFluent builder for constructingAgentStateinstances. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionagentId()Returns the value of theagentIdrecord component.Returns the value of theagentNamerecord component.Returns the value of theagentTyperecord component.static AgentState.AgentStateBuilderCreates a new builder for constructingAgentStateinstances.data()Returns the value of thedatarecord component.final booleanIndicates whether some other object is "equal to" this one.<T> TRetrieves a typed data value by key.getMetadata(String key) Retrieves a metadata value by key.final inthashCode()Returns a hash code value for this object.metadata()Returns the value of themetadatarecord component.savedAt()Returns the value of thesavedAtrecord component.status()Returns the value of thestatusrecord component.final StringtoString()Returns a string representation of this record class.longversion()Returns the value of theversionrecord component.
-
Constructor Details
-
AgentState
public AgentState(String agentId, String agentName, String agentType, AgentStatus status, Map<String, Object> data, Map<String, String> metadata, long version, Instant savedAt) Canonical constructor with defensive copying and default values.This constructor ensures:
- Collections are immutable (defensive copy)
- Null values get sensible defaults
- Invariants are maintained
- Throws:
NullPointerException- if agentId is null
-
-
Method Details
-
builder
Creates a new builder for constructingAgentStateinstances.The builder pattern is the recommended way to create state objects, especially when dealing with multiple fields or creating modified copies of existing state.
- Parameters:
agentId- the required agent identifier- Returns:
- a new builder instance
- Throws:
NullPointerException- if agentId is null
-
getData
Retrieves a typed data value by key.This is a convenience method that performs type casting for you. Use this instead of manually casting values from the
datamap.Type Safety: This method performs an unchecked cast. Ensure you're requesting the correct type, or a
ClassCastExceptionwill be thrown at runtime.Example:
Integer count = state.getData("ordersProcessed", Integer.class); List<String> batch = state.getData("currentBatch", List.class); CustomOrder order = state.getData("pendingOrder", CustomOrder.class);- Type Parameters:
T- the expected type of the value- Parameters:
key- the data keytype- the class of the expected type (used for clarity, not actual type checking)- Returns:
- the value cast to type T, or null if the key doesn't exist
- Throws:
ClassCastException- if the value cannot be cast to type T
-
getMetadata
Retrieves a metadata value by key.This is a convenience method equivalent to calling
state.metadata().get(key), but more readable.- Parameters:
key- the metadata key- Returns:
- the metadata value, or null if the key doesn't exist
-
toString
Returns a string representation of this record class. The representation contains the name of the class, followed by the name and value of each of the record components. -
hashCode
public final int hashCode()Returns a hash code value for this object. The value is derived from the hash code of each of the record components. -
equals
Indicates whether some other object is "equal to" this one. The objects are equal if the other object is of the same class and if all the record components are equal. Reference components are compared withObjects::equals(Object,Object); primitive components are compared with '=='. -
agentId
Returns the value of theagentIdrecord component.- Returns:
- the value of the
agentIdrecord component
-
agentName
Returns the value of theagentNamerecord component.- Returns:
- the value of the
agentNamerecord component
-
agentType
Returns the value of theagentTyperecord component.- Returns:
- the value of the
agentTyperecord component
-
status
Returns the value of thestatusrecord component.- Returns:
- the value of the
statusrecord component
-
data
Returns the value of thedatarecord component.- Returns:
- the value of the
datarecord component
-
metadata
Returns the value of themetadatarecord component.- Returns:
- the value of the
metadatarecord component
-
version
public long version()Returns the value of theversionrecord component.- Returns:
- the value of the
versionrecord component
-
savedAt
Returns the value of thesavedAtrecord component.- Returns:
- the value of the
savedAtrecord component
-