【问题标题】:lein uberjar taking foreverlein uberjar 永远服用
【发布时间】:2021-05-03 10:34:32
【问题描述】:

我想创建一个 leiningen 应用程序的 uberjar。我的配置是:

:uberjar {:omit-source true
             :aot :all
             :uberjar-name "myapp.jar"
             :source-paths ["env/prod/clj" ]
             :resource-paths ["env/prod/resources"]}

但是在执行lein uberjar 时,我发现项目中的文件正在编译,但是编译卡在包含大部分代码的文件上,持续了十分钟并且还在计数。此文件不超过 140 行。

【问题讨论】:

  • 我的猜测是,在该命名空间的顶层有一些定义的东西,它有副作用。例如。一些数据库连接或启动一些服务器或其他任何东西。
  • 是的,我刚刚发现这一行: (defonce server (http/start-server server-handler {:port 8982})) 导致挂起。如何解决这个问题?
  • 不要把这样的东西放在顶层。编写一个函数,启动这个服务器。然后从你的主要调用它。对于开发,您可以从 REPL 运行该功能,或者您可以在您的 user-ns 中添加一些重新加载/重新启动逻辑。 defonce 仅表示它一旦存在就不会被重新定义。

标签: clojure uberjar


【解决方案1】:

TL;DR:从不def 副作用


如 cmets 所述:

...我刚刚发现这条线:(defonce server (http/start-server server-handler {:port 8982})) 导致挂起。

不要把这样的东西放在顶层。

defonce 仅表示它一旦存在就不会被重新定义(所以在这种情况下 它将防止重新加载时出现一些“端口已在使用”错误。

摆脱困境的方法

编写一个函数,启动这个服务器。然后从你的主要调用它。为了 开发,你可以从 REPL 运行该功能,或者你可以洒一些 在你的用户 ns 中重新加载/重启逻辑。

另一个选项可能是使用delay:它只会在获得derefed 后执行代码。

你要处理的“资源绑定”越多,就越有系统性 方法将为您的应用程序提供更好的结构。例如。看看:

那么,为什么在 def 中放置阻塞的东西或副作用会有问题呢?

Clojure 编译器的工作方式是实际“运行”代码。所以compile基本上就是:

  1. 启用生成字节码并将其写为 .class 文件
  2. 加载命名空间并“运行”它

这意味着,在编译时,顶级副作用被执行。 因此,def 中的阻塞操作将阻塞编译(这是相当 明显),否则您的 CI 服务器将无法编译,因为它无法连接到 数据库等

很好地解释了 Clojure 中代码生成的工作原理:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    • 2019-01-21
    • 1970-01-01
    • 2011-04-10
    • 1970-01-01
    • 2018-04-25
    • 2016-02-12
    相关资源
    最近更新 更多