Hello! I've been using a few of the functions from clojure.tools.build.api
in a future
and I sporadically see this error...
Execution error (IllegalStateException) at clojure.tools.build.api/create-basis (api.clj:154).
Attempting to call unbound fn: #'clojure.tools.build.tasks.create-basis/create-basis
From what I see in tools.build...
(defn create-basis
([]
((requiring-resolve 'clojure.tools.build.tasks.create-basis/create-basis)))
([params]
((requiring-resolve 'clojure.tools.build.tasks.create-basis/create-basis) params)))
...the code is only really using requiring-resolve
to execute another function. Diving deeper into requiring-resolve
I can see that the first call to resolve
is not synchronized with the same lock that the serialized-require
function uses...
(defn- serialized-require
[& args]
(locking clojure.lang.RT/REQUIRE_LOCK
(apply require args)))
(defn requiring-resolve
[sym]
(if (qualified-symbol? sym)
(or (resolve sym)
(do (-> sym namespace symbol serialized-require)
(resolve sym)))
(throw (IllegalArgumentException. (str "Not a qualified symbol: " sym)))))
First, is it possible requiring-resolve
is actually returning clojure.lang.Var$Unbound
from the first call to resolve
when another thread is in the process of requiring that namespace via serialized-require
? Assuming so, should tools.build
(and I guess by extension most Clojure code) avoid using the ((requiring-resolve 'some-other/function))
pattern? Is it possible requiring-resolve
could be modified to be thread safe?
Thanks!