Question

I created a compojure app using lein new compojure mongotest with lein 2.0, and a Procfile web: lein ring server-headless $PORT. This worked fine, but now when I add

(def mongolab-url (System/getenv "MONGOLAB_URI"))
(println "mongolab-url")
(println mongolab-url)
(mg/connect-via-uri! mongolab-url)

when I try git push heroku master Heroku eventually gives me

   Compiling mongotest.handler
   mongolab-url
   nil
   Exception in thread "main" java.lang.NullPointerException, compiling:(handler.clj:13:1)
    ... 25 more
   Compilation failed: Subprocess failed
   Error encountered performing task 'compile' with profile(s): 'production'
   Suppressed exit
!  Failed to build.
!  Push rejected, failed to compile Clojure (Leiningen 2) app

I added these lines at the top level of handler.clj. Some of the older documentation I see the connection is created in main, but that must have been for older versions of compojure, as there's no main anymore (that I've found) in the generated app. Where should the connection get established in the current version? (Or is my Procfile not right?)

(Yes, MONGOLAB_URI is defined in heroku config)

Was it helpful?

Solution

The answer that worked for me and seems most idiomatic is to put the above connection into a function init in that same file (myproject/handler.clj)

(defn init[] (mg/connect-via-uri! (System/getenv "MONGOLAB_URI")))

and update the project.clj file ring descriptor line from

:ring {:handler myproject.handler/app}

to

:ring {:handler myproject.handler/app :init myproject.handler/init}

OTHER TIPS

You don't want side-effects (such as opening a database connection) to happen at namespace load time, which is effectively compile time. Often you can get away with such things, when you are compiling your code when clojure starts up, but in this case heroku is pre-compiling your app into a jar so that it can serve it up more quickly. Now, at compile time, you try to read the PORT environment variable; but it is not set until heroku tries to actually run your app.

The solution is to create it only at runtime, eg by doing so in -main, or in some other function, or by defining it as a delay which you only force at runtime.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top