Skip to content

Instantly share code, notes, and snippets.

@samn
Created October 16, 2013 21:45
Show Gist options
  • Save samn/7015449 to your computer and use it in GitHub Desktop.
Save samn/7015449 to your computer and use it in GitHub Desktop.
This shows a technique for waiting for an asynchronous operation (here persistence) to occur without using locks. This is useful if we normally want this operation to occur asynchronously (in a future thread pool) but would like to wait for its completion at exceptional times. For example, it may be fine to periodically persist data asynchronous…
(defn wait-for-persistence
"Dereferences and waits on the value of persistence-lock-atom,
if the value is dereferenceble & returns the dereferenced value.
Otherwise returns nil."
[persistence-lock-atom]
(when (instance? clojure.lang.IDeref @persistence-lock-atom)
;; This could deref with a timeout by using `deref` instead of `@`
@@persistence-lock-atom))
(defn persist!
"Persist some resource.
Noops if persistence is already happening."
[persistence-lock-atom]
(let [completion-promise (promise)]
(future
;; compare-and-set! returns true if the set happened, i.e. if the
;; old-val was false which means persistence isn't already happening.
;; Set persistence-lock-atom to a promise to communicate the completion of
;; this async persistence.
(when (compare-and-set! persistence-lock-atom false completion-promise)
(do-something-that-persists)
(deliver completion-promise :complete)
;; reset the lock atom so the next persistence can happen. if someone was waiting
;; on the completion promise to see if this persistence occurred they'll see the
;; deliver above.
(reset! persistence-lock-atom false)))))
(let [persistence-lock (atom false)]
(persist! persistence-lock)
(wait-for-persistence persistence-lock))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment