Browse Learn Clojure Foundations as a Java Developer

Read Agent State Without Lying to Yourself

Read an agent as a completed-state snapshot, use await only when blocking is intentional, and avoid designs that need immediate results from asynchronous actions.

Reading an agent is easy: use @agent or deref. Interpreting the read correctly is the important part.

An agent read returns the latest completed state. It does not mean every action you recently sent has already run unless you deliberately wait.

Snapshot Reads

1(def totals (agent {:processed 0}))
2
3(send totals update :processed inc)
4
5@totals
6;; May be {:processed 0} or {:processed 1}

That behavior is correct. The caller queued asynchronous work and then immediately read a snapshot.

Waiting Deliberately

Use await when the current thread intentionally needs actions already sent to an agent to finish.

1(send totals update :processed inc)
2(await totals)
3@totals
4;; => {:processed 1}

Blocking should be explicit and rare in request-handling paths. If a caller needs the new value immediately, an atom, ref transaction, future, promise, or direct function call may be a better fit.

Read Pattern Table

Need Pattern Caution
Display current progress @agent It is a snapshot, not a guarantee that all queued work is done.
Test an agent example send, then await, then read Keep tests from racing asynchronous work.
Return immediate result to caller Avoid agent or use a different coordination tool Agents intentionally decouple caller and update.
Shutdown a command-line process await and shutdown-agents when needed Do not leave background agent threads running accidentally.

Java Migration Notes

Java developers often expect a submitted task to produce a Future that can be joined for a result. Agent actions are different: they update the agent’s state. The action result becomes the next state, not a returned value to the sender.

If your design wants “submit work and get a result,” choose the tool that says that directly. If your design wants “serialize updates to this state value,” an agent fits.

Knowledge Check

### What does `@totals` return after an action has been sent? - [x] The latest completed state at the moment of the read. - [ ] A future that always waits for every queued action. - [ ] The result of the most recently sent action only. - [ ] A lock on the agent. > **Explanation:** Agent reads are snapshots. Recently queued actions may still be pending. ### When is `await` appropriate? - [x] When blocking until already-dispatched actions finish is intentional. - [ ] Around every agent read in production code. - [ ] Inside every agent action. - [ ] To make an agent durable. > **Explanation:** `await` is useful for tests, shutdown, and explicit synchronization points. It should not be a reflex. ### What should you choose if the caller needs an immediate computed result? - [x] A direct call, future, promise, atom, or ref transaction depending on the coordination need. - [ ] Always an agent. - [ ] A dynamic Var. - [ ] `shutdown-agents`. > **Explanation:** Agents are for asynchronous state transitions. Immediate return values call for a different abstraction.
Revised on Saturday, May 23, 2026