Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I make lein ring server-headless run on a specific servlet context?

I have a Ring app that through deploys to production as an uberwar thing; myservice.war. In production the WAR file gets tossed into Jetty where it runs in a context that follows its name

$ curl -i -X GET http://myservice.qa1.example.com:8080/myservice/healthz
HTTP/1.1 200 OK
...

When I run locally through lein ring, I need it to run in the same context; myservice.

$lein ring server-headless
2015-10-14 14:04:03,457  level=INFO [main] Server:271 - jetty-7.6.13.v20130916
2015-10-14 14:04:03,482  level=INFO [main] AbstractConnector:338 - Started [email protected]:10313
Started server on port 10313

But the same curl goes all 404 on me locally.

$ curl -i -X GET http://localhost:10313/myservice/healthz
HTTP/1.1 404 Not Found
...

The lein ring thing deployed it onto the root context.

$ curl -i -X GET http://localhost:10313/healthz
HTTP/1.1 200 OK
...

Whats up with that? How do I direct lein ring to deploy into a context name of my choosing? I need curl -i -X GET http://localhost:10313/myservice/healthz to work from lein ring

like image 295
Bob Kuhar Avatar asked Nov 10 '22 03:11

Bob Kuhar


1 Answers

One way to work around this issue is to create the second (standalone) set of routes for your app. You also create the second handler for the standalone case. Then you can use Leiningen profiles to specify different handlers for the standalone case and the uberwar case. The default profile is used when running the app standalone. The :uberjar profile is used when the uberwar is created. As a result, your standalone handler going to be used with lein ring server-headless and your regular handler is going to be used when the war is deployed into a container.

Not much additional code needed to create the second set of routes. You can just wrap the existing routes in a context of your choosing. Suppose the following are your routes and ring handler:

(defroutes app-routes
  (GET "/healthz" [] "Hello World")
  (route/not-found "Not Found"))

(def app
  (wrap-defaults app-routes site-defaults))

Additional routes and handler for the standalone case would look like this:

(defroutes standalone-routes
  (context "/myservice" req app-routes)
  (route/not-found "Not Found"))

(def standalone-app
  (wrap-defaults standalone-routes site-defaults))

Now, onto lein-ring configuration in project.clj. We want the default ring handler to point to standalone-app. The ring handler for the uberwar should point to app. The :ring entry in the project map in project.clj should look like this (adjust for your actual namespace):

:ring {:handler myservice.handler/standalone-app}

Also, merge the following into your :profiles map in project.clj:

:uberjar {:ring {:handler myservice.handler/app}}

Please be sure to use the latest version of the lein-ring plugin. Version 0.9.7 worked for me. Earlier versions, like 0.8.3, did not work because they did not use the :uberjar profile when running the uberwar task.

If you do all this, and assuming your war file is called myservice.war, the context part of the URI is going to be the same whether your app is started with lein ring server-headless or if the war file is deployed in Jetty.

$ curl http://localhost:[port]/myservice/healthz
like image 192
ez121sl Avatar answered Nov 15 '22 07:11

ez121sl