I'm building a Clojure Noir web application to run as a WAR file in CloudFoundry.
In my project.clj I have:
:ring {:handler appname.server/handler}
In server.clj I create a handler using Noir:
(def handler (noir.server/gen-handler {:ns 'appname}))
I build the WAR file using a lein ring plugin:
lein ring uberwar
Then push to CloudFoundry using:
vmc push appname
The request handler works fine and I can browse to the URL of the application just fine.
So the question is: what is the correct way to do initialization when the application is started?
I can do the following in server.clj:
(when (System/getenv "VCAP_APPLICATION")
(init-func))
But there are a couple problems with that. First, it seems like that is doing the initialization at the wrong time (when the code is read/eval'd rather than on app start). Second, the protector is specific to CloudFoundry and I certain there is a proper general WAR way to do this.
I think this is the purpose of the contextInitialized method on the ServletContextListener but how do I hook that in with Noir/ring?
Figured it out by looking at ring source for WAR handling
The project.clj :ring map takes an :init keyword like so:
:ring {:init appname.server/my-init
:handler appname.server/handler}
The my-init function will be called on application startup.
Caveat: this apparently balloons the amount of memory needed by the application for initial startup. 128M was sufficient without the initialization. With the initialization code , the app startup failed, so I had to bump the memory to 256M. I suspect that with the init code the JVM doesn't have time to garbage collect before the Clojure code is compiled/executed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With