Fully asynchronous processing model with the callback agent in Clojure

The article Agents in Clojure is pretty old, i.e. “Created 24.12.2009”, and often incorrect, i.e. “Submitting a task to an agent must be done in a transacted section (dosync)” so use with a great care, but nevertheless inspired me to try out the fully asynchronous processing model with the callback agent.

The example is to send a computation (a function) to an agent that in turn becomes the callback agent for another. Once the callee agent finishes its computation, it calls its caller (the callback agent).

In ASCII art-like drawing it would be as follows:

— (initial-message agent-callee async-computation) —> agent-caller — (async-computation agent-caller callback-message) —> agent-callee — (callback-message) —> agent-caller

(ns pl.japila.clojure.callback-agents
  (:gen-class))

(def agent-caller (agent 0))

(def agent-callee (agent 0))

(defn callback-message [agent-current-state]
  (println "--> Received callback message")
  (inc agent-current-state))

(defn initial-message [agent-current-state agent-to-call f]
  (let [callback-agent *agent*]
    (println "--> Initialization begun. Calling " agent-to-call " with f: " f)
    (send-off agent-to-call f callback-agent callback-message)
    (inc agent-current-state)))

(defn async-computation [agent-current-state callback-agent f]
  (println "<-- Going sleep for 1 sec")
  (Thread/sleep 1000)
  (println "<-- Calling callback agent: " callback-agent)
  (send-off callback-agent f)
  (inc agent-current-state))

(defn demo []
  (send-off agent-caller initial-message agent-callee async-computation)
  (await agent-caller agent-callee)
  (println "agent-caller: " @agent-caller)
  (println "agent-callee: " @agent-callee)
  (shutdown-agents))

(defn -main []
  (time
    (demo)))

Save the script to pl/japila/clojure/callback_agents.clj and execute as follows (mind the dot ‘.’ in the -cp):

java -cp ~/.m2/repository/org/clojure/clojure/1.4.0/clojure-1.4.0.jar:. clojure.main --main pl.japila.clojure.callback-agents

With that I know HOW to use agents in Clojure much better, but still uncertain about WHY or WHEN. Any ideas for possible use cases?

Be Sociable, Share!
This entry was posted in Languages.

One Response to Fully asynchronous processing model with the callback agent in Clojure

  1. Eric Normand says:

    One good use case for Agents is simple concurrency. Make N agents (in a vector), that run in a loop (send to themselves). The producer/consumer pattern is very simple in Clojure. N producer agents and M consumer agents all acting on a queue (in a ref).

Leave a Reply

%d bloggers like this: