请分享您的想法,参与2024 Clojure 状态调查!

欢迎!请查看关于页面以了解此平台的相关信息。

+2
Clojure CLI

https://github.com/clojure/brew-install/pull/8中所述,在我们的持续集成(CI)中,我们需要并行运行同一项目的多个 clojure 任务。这有时会导致以下错误:

Refreshing classpath
Error building classpath. Can't create directory: /path/to/project/.cpcache

我的理解是,它在https://github.com/clojure/tools.deps/blob/master/src/main/clojure/clojure/tools/deps/util/io.clj#L53-56执行,那里我们首先检查一个目录是否存在,然后创建它。

(when-not (.exists parent)
  (when-not (.mkdirs parent)
    (let [parent-name (.getCanonicalPath parent)]
      (throw (ex-info (str "Can't create directory: " parent-name) {:dir parent-name})))))

如果另一个进程在我们检查其存在之后创建它,则 .mkdirs 返回 false,并导致此进程失败。一个可能的解决方案是在像这里那样再次检查目录是否存在。

(when-not (.exists parent)
  (when-not (.mkdirs parent)
    (when-not (.exists parent)
      (let [parent-name (.getCanonicalPath parent)]
        (throw (ex-info (str "Can't create directory: " parent-name) {:dir parent-name}))))))

1 条回答

+1

我们在https://clojure.atlassian.net/browse/TDEPS-250中有一个关于此问题的工单。

我对此进行了调查,在我看来,这里真正的难题在于Java的mkdirs并没有解释为什么目录无法创建。通常克服mkdirs竞态冲突的方法是检查EEXIST错误,如果那是错误,则继续操作不报错,因为我们知道其他进程赢得了竞赛。

当它输掉竞赛时,java.nio.path.createDirectories会抛出FileAlreadyExistsException。

我发现该仓库中的其他代码已经使用了java.nio,所以我猜将mkdirs转换为createDirectories应该是可能的。

希望这有助于您!
...