await

added
1.0

ns
clojure.core

type
function

(await & agents)

Blocks the current thread (indefinitely!) until all actions
dispatched thus far, from this thread or agent, to the agent(s) have
occurred.  Will block on failed agents.  Will never return if
a failed agent is restarted with :clear-actions true.

                ;; construct a simple agent
(def *agnt* (agent {}))

(send-off *agnt* (fn [state] 
               (Thread/sleep 10000)
               (assoc state :done true)))
;;=> <Agent@5db18235: {}>

;; blocks till the agent action is finished
(await *agnt*) 
;;=> nil
            
                (import '(java.io BufferedWriter FileWriter))

;; Generally the agent can be sent messages asynchronously, send and forget.
;; In some cases a rendezvous is needed, e.g. in the case of an output file.

(def write-out 
  (agent {:handle (clojure.java.io/writer "results.txt" )
          :last-msg ["init"]}
        :validator (fn [state] 
                       (and (contains? state :handle) (contains? state :last-msg))) 
        :error-handler (fn [result] 
                           (println "invalid result") )))

(defn write-a-line [state msg nap] 
  (.write (:handle state) (str msg " line " "\
")) 
  (let [new-state (update-in state [:last-msg] into [msg])]
    (println "message : " msg " : " new-state)
    (Thread/sleep nap)
    new-state))



;; these all have the same return value
(send-off write-out write-a-line "first" 2000)
(send-off write-out write-a-line "second" 1000)
(send-off write-out write-a-line "third" 5000)
(send-off write-out write-a-line "fourth" 1000)
@write-out
;;=> {:handle #<BufferedWriter java.io.BufferedWriter@e175cca>, :last-msg ["init"]}

(time (await write-out))
;; 9000.307 msecs

;; here we can see that the await causes the thread to block
;; until the agent's queue is empty.
@write-out
;;=> {:handle #<BufferedWriter java.io.BufferedWriter@e175cca>, 
;;    :last-msg ["init" "first" "second" "third" "fourth"]}

;; But wait the "result.txt" file is empty!
;; We need to close the file handle.
;; And now that we know the agent's queue is empty we
;; are free to close it.
;; This could do this in the current thread with the dereferenced
;; agents :handle '(.close (:handle @write-out))' 
;; but it is probably better to be formal and let the agent do it.
(defn close-the-agent [state] 
  (.close (:handle state)) 
  state)

(send-off write-out close-the-agent)

;; And the contents of "result.txt" are: (less the leading '; ')
; first line
; second line
; third line
; fourth line