Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialization hook for Clojure Noir WAR/Servlet (CloudFoundry)

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?

like image 771
kanaka Avatar asked Feb 01 '12 23:02

kanaka


1 Answers

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.

like image 200
kanaka Avatar answered Oct 10 '22 22:10

kanaka