Search code examples
clojurecompilationleiningen

Clojure compile time


I'm testing out Clojure for the first time, and wanted to write a simple websocket client application. I've found the library https://github.com/stylefruits/gniazdo and got the code to work (using lein run). However, compiling the code into a jar (either with lein jar or lein uberjar is either stuck or takes ages (aborted after ~1h))

steps:

  1. lein new app testing
  2. modified src/testing/core.clj and project.clj (see below)
  3. lein jar (or lein uberjar)

For simplicity I've have this very simple code, which already takes ages to compile into a jar:

(ns testing.core
  (:gen-class))

(require '[gniazdo.core :as ws])

(def socket
    (ws/connect
            "wss://some.url.com/"))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (ws/close socket))

project.clj:

(defproject testing "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]
                 [stylefruits/gniazdo "1.0.1"]]
  :main ^:skip-aot testing.core
  :aot [testing.core]
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

output of running lein jar:

$lein jar
Compiling testing.core
2017-12-11 14:15:14.813:INFO::main: Logging initialized @1352ms

and nothing aferwards. Is this normal behaviour (and it just takes ages to compile) or am I missing something here? Clojure looks very interesting, but if it takes even for such a small program hours to compile, deployment could be a problem in my circumstances.


Solution

  • When that namespace is compiled Ahead of Time (:aot [testing.core] in your project.clj), this code gets evaluated during compilation:

    (def socket
      (ws/connect "wss://some.url.com/"))
    

    This is likely what's causing the hang. The compiler never moves on from this because it has made a blocking call.

    1. You could remove the :aot directive if you don't need it (and you probably don't). I think this can be a somewhat confusing default when creating a new Leiningen project.

    2. You could do something like wrap that socket/conn in a delay:

      (def socket (delay (ws/connect "wss://some.url.com/")))
      

      And then deref/@ it wherever you need the value. This just delays evaluation of ws/connect until you ask.