reagent-project / reagent-template

A Leiningen template for projects using Reagent.
MIT License
394 stars 55 forks source link

App deployed to Heroku cannot start in 60 seconds #25

Closed ilyabo closed 9 years ago

ilyabo commented 9 years ago

I am having difficulties deploying an app built with the template to Heroku. The generated Procfile tries to run the following task in a web worker:

 web: lein with-profile production trampoline ring server

When executing this task Leiningen begins downloading a gazillion of dependencies including the ones unnecessary for production (e.g figwheel), in spite of the fact that the standalone .jar file had already been built by the slug compiler. This results in the following error:

2014-12-29T00:58:50.506270+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
2014-12-29T00:58:50.506504+00:00 heroku[web.1]: Stopping process with SIGKILL
2014-12-29T00:58:51.285273+00:00 heroku[web.1]: Process exited with status 137
2014-12-29T00:58:51.290057+00:00 heroku[web.1]: State changed from starting to crashed

I tried changing the Procfile so that the jar file is executed directly:

web: java $JVM_OPTS -jar target/myapp.jar 

But this doesn't work either, as the ring handler namespace does not include the -main method, and for some reason, lein uberjar does not generate a self-executable ring server.

What's the right way to run the app on Heroku and to avoid fetching dependencies in the web worker?

yogthos commented 9 years ago

you should be generating a standalone runnable jar using leing ring uberjar instead of lein uberjar. Once built that way you should be able to use web: java $JVM_OPTS -jar target/myapp.jar to run it. I'll update the procfile to use that method.

ilyabo commented 9 years ago

Thanks Dmitry! But how do I make Heroku run lein ring uberjar instead of lein uberjar when the slug is compiled? Do I need a special buildpack for that?

yogthos commented 9 years ago

Hmm, there does appear to be one here, but I haven't actually tried running it. I've used the lein trampoline approach myself, so this will be interesting to figure out. :)

yogthos commented 9 years ago

hmm the buildpack still uses lein 1.7 so that's quite out of date

ilyabo commented 9 years ago

I finally decided to add a main function starting jetty to the handler namespace:

 (:require [ring.adapter.jetty :as ring])
 ...
 (defn -main [& args]
   (let [port (Integer/parseInt (or (System/getenv "PORT") "8080"))]
     (ring/run-jetty #'app {:port port :join? false})))

This way there is no need for a buildpack. The Procfile template must look like this then:

  web: java $JVM_OPTS -jar target/{{name}}.jar -m {{name}}.handler

Is there any downside to this?

yogthos commented 9 years ago

There isn't any difference for uberjar, and lein ring will pretty much do the same thing. The main reason I'm using lein-ring is because it can also produce an uberwar for container deployment and it allows specifying the handler/init/destroy functions in the project file.

yogthos commented 9 years ago

It might be worthwhile to add a main as well for heroku deployment or running with http-kit.

ilyabo commented 9 years ago

Ok, I see. Would it make sense then to move the dev-only dependencies (figwheel, piggieback, weasel etc) to the :dev profile in project.clj so that they are not downloaded in production?

yogthos commented 9 years ago

Yeah that would probably be a good plan. :)

ilyabo commented 9 years ago

But this would also require excluding the dev .clj files from the compilation.

yogthos commented 9 years ago

shouldn't those already be excluded based on the profile though?

ilyabo commented 9 years ago

I think it is currently only true for the .cljs files

yogthos commented 9 years ago

ah right, so the dev.clj should probably be moved over to the env folder as well then.

ioRekz commented 9 years ago

What's the preferred way to deploy to heroku right now ? You proposed a Procfile running the uberjar but the template one still use lein trempoline. Also, the template Procfile is -web: lein with-profile production trampoline ring server And I think the leading dash make it be ignored by heroku so it uses its default clojure web proctype

yogthos commented 9 years ago

The dash is a typo, but otherwise the lein version should be fine for most cases. The alternative would be to add a main and use web: java $JVM_OPTS -jar target/myapp.jar in the Procfile as described above.

ioRekz commented 9 years ago

Ok, I had to use this one to avoid the 60sec timeout

On Sat, Jan 24, 2015 at 10:59 PM, Dmitri Sotnikov notifications@github.com wrote:

The dash is a typo, but otherwise the lein version should be fine for most cases. The alternative would be to add a main and use web: java $JVM_OPTS -jar target/myapp.jar in the Procfile as described above.

— Reply to this email directly or view it on GitHub https://github.com/reagent-project/reagent-template/issues/25#issuecomment-71339550 .

yogthos commented 9 years ago

I think I'll just add a main for heroku to avoid the confusion

ioRekz commented 9 years ago

Yep, would be useful :p

On Sat, Jan 24, 2015 at 11:11 PM, Dmitri Sotnikov notifications@github.com wrote:

I think I'll just add a main for heroku to avoid the confusion

— Reply to this email directly or view it on GitHub https://github.com/reagent-project/reagent-template/issues/25#issuecomment-71340030 .

yogthos commented 9 years ago

ok just push out a new version with a server.clj that's used as a main when building using lein uberjar this will make it easier to add support for http-kit in the future as well since lein-ring doesn't support it either.

theronic commented 6 years ago

A previously working build threw an R10 and H10 on a redeploy. Redeploying fixed it - there must be some cache that needs to heat up on Heroku. Worrying that it's not dependable. May also have something to do with queued up requests hitting cold app at once and triggering an alarm that causes an H10 state.