The docs for swap! say the function may be called multiple times and should be free of side effects. Code in the wild still logs from inside it.
(def hits (atom 0))
(defn record! [id]
(swap! hits (fn [n]
(println "counting" id)
(inc n))))
The atom's value is right whatever happens, because only one attempt commits. The println is not part of that commit. When two threads race, the losing attempt has already printed and runs again, so a line can appear twice for one call. Same shape as a side effect inside dosync, only cheaper to hit because nothing coordinates. The fix I use is swap-vals!, which returns the old and the new value, and doing the logging after it returns.