Clojure - Ring uberjar specify port - clojure

How can I generate a standalone ring uberjar that listens to a given port ?
When developing I launch my app with the following leiningen/ring command, in which I can specify the port :
lein with-profile dev ring server-headless 9696
Now I want to deploy it, so I ran :
lein with-profile prod ring uberjar 9696
But I got an error :
Error encountered performing task 'ring' with profile(s): 'prod'
clojure.lang.ArityException: Wrong number of args (2) passed to: uberjar/uberjar
So I added a :portin my project.clj :
:ring {:handler img-cli.handler/handler
:init img-cli.handler/init
:destroy img-cli.handler/destroy
:port 9696}
lein with-profile prod ring uberjar
java -jar my-jar.jar
But then I see in the logs : Started server on port 3000
How do I generate an uberjar with the port that I want ?
Note : just in case, I'm using compojure.

It turns out that my use of the profile was problematic.
A closer looks at the profile documentation yields :
To activate a profile in addition to the defaults, prepend it with a
+:
$ lein with-profile +server run
Therefore I had to use lein with-profile +prod ring uberjar 9696 (notice the +).

Related

Remote REPL no output, how to dublicate output in PrintWriter?(Clojure)

Cannot connect remote REPL properly
Here are the steps I do:
Start local repl instance:
lein repl
Connect to local by remote repl instance(I do it through Intellij IDEA)
After this, every output in code goes only in local repl, in remote one there are nothing
What I need: to see all outputs in both repl instances
I have found partial solution, this code rebinds output of one repl to another. Just run it in remote one, and all output will go to it
(defn rebind-output []
(prn "Rebinding output...")
(System/setOut (PrintStream. (WriterOutputStream. *out*) true))
(System/setErr (PrintStream. (WriterOutputStream. *err*) true))
(alter-var-root #'*out* (fn [_] *out*))
(alter-var-root #'*err* (fn [_] *err*)))
out - is intstance of PrintWriter
However what I need is: see BOTH repls outputing the same, how to do it?
I can't seem to think that you are confused about how to connect to an existing REPL (the one you launch from the command line with lein repl). Did you check the section Remote REPLs in the Cursive manual?
Generally, you want only one of these:
Launch the REPL from Intellij itself on a project that is already managed with Leiningen (eg. it already has a project.clj file), or
Connect to an already running REPL, one that is running on the same host, or in a different machine.
If you are starting lein repl yourself in a console, you'll see that it prints some messages on startup:
$ lein repl
nREPL server started on port 39919 on host 127.0.0.1 - nrepl://127.0.0.1:39919
In this example, the server started listening on my own host (127.0.0.1 or localhost) on port 39919 (this port will change each time you launch the REPL with lein repl). You'll need to enter these values in Intellij to be able to connect to this REPL.

How to configure Jetty settings in project.clj and use Lein Ring in Clojure?

I would like to add some configuration to Jetty Adapter and run it with the lein-ring plugin, but i could not find any information.
I can run this configured from the main function by using lein run.
(jet/run-jetty main-handler {:port 8080 :join? false})
But I want to set those configurations in the project.clj so I can use "lein ring server".
The lein-ring documentation suggests you can put a map of options for your ring adapter in the project.clj file, like this:
:ring {:handler hello-world.core/handler
:adapter {:join? false
:port 8080}}
Though you probably do not want to use :join? false I'd think.

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 SelectChannelConnector#0.0.0.0: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
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

How to get Clojure Compojure app to run headless via compiled jar within Docker container?

Update: this question has changed since the original set of commenters left responses. Apologies for any confusion.
This is my code repository https://github.com/Integralist/spurious-clojure-example you can use it as an example for what I'm working with.
Note that the above repo relies on a library I've not yet published to Clojars (as I'm still testing it - hence this question opened). You can see the source code of the library here: https://github.com/Integralist/spurious-clojure-aws-sdk-helper
I have a "hello world" Clojure web app written with Compojure that I have working fine when run using lein ring server and lein run (as I have a -main function now created). It also runs to a certain extent when compiled down into a jar and I run java -jar app.jar.
My problem now is that if I try to run the default java -jar app.jar from within a Docker container I get the following error telling me...
spurious-clojure-example is starting
2015-02-14 00:58:03.812:INFO:oejs.Server:jetty-7.x.y-SNAPSHOT
2015-02-14 00:58:03.854:INFO:oejs.AbstractConnector:Started SelectChannelConnector#0.0.0.0:8080
Started server on port 8080
Exception in thread "main" java.awt.HeadlessException:
My code is currently using a -main function like so...
(ns spurious-clojure-example.repl
(:use spurious-clojure-example.handler
ring.server.standalone
[ring.middleware file-info file])
(:gen-class))
(defonce server (atom nil))
(defn get-handler []
(-> #'app
(wrap-file "resources")
(wrap-file-info)))
(defn start-server
"used for starting the server in development mode from REPL"
[& [port]]
(let [port (if port (Integer/parseInt port) 8080)]
(reset! server
(serve (get-handler)
{:port port
:init init
:auto-reload? true
:destroy destroy
:join true}))
(println (str "You can view the site at http://localhost:" port))))
(defn stop-server []
(.stop #server)
(reset! server nil))
(defn -main []
(start-server))
...but how do I get the server to start headless? I can't quite follow the Compojure boilerplate code to decipher where or how it knows when to run headlessly or via browser?
I know that on the command line you can do lein ring server-headless so what's the programmatic equivalent of that?
Because ring-server is primarily meant for development, it tries to open a browser when the server starts. This fails with a java.awt.HeadlessException on platforms without a GUI. You'll want to set the :open-browser? option to false to prevent this.
From the offical Docker docs on EXPOSE
The EXPOSE instructions informs Docker that the container will listen
on the specified network ports at runtime. Docker uses this
information to interconnect containers using links (see the Docker
User Guide) and to determine which ports to expose to the host when
using the -P flag. Note: EXPOSE doesn't define which ports can be
exposed to the host or make ports accessible from the host by default.
To expose ports to the host, at runtime, use the -p flag or the -P flag.
So if you're setting the ring server port manually in your project.clj, ensure that you're using the same port also in your Dockerfile and then provide a mapping via -p or -P when starting docker.
I can't say for sure but I believe that your headless error message doesn't contribute to your problem.

Issue with lein ring uberjar and profiles

I am having troubles to make lein ring uberjar work with multiple profiles.
The following works:
lein new luminus profile-issue
cd profile-issue
lein ring uberjar
java -jar target\profile-issue-0.1.0-SNAPSHOT-standalone.jar
Now, when working with multiple profiles the following change to project.clj is important.
;add key to project.clj
:target-path "target/%s/"
Next attempt
lein clean
lein ring uberjar
java -jar target\profile-issue-0.1.0-SNAPSHOT-standalone.jar
Error: Could not find or load main class profile_issue.handler.main
The reason why it's important to split the target path into subdirectories when working with multiple profiles is explained here, around line 250. In a nutshell, when using :target-path "target/ you'll end up in troubles because different profiles compile into the same directory and when you start the REPL without a lein clean, you don't really know what you get.
And btw, when using :target-path "target/%s/" the jar and uberjar don't end up in the same directory which is weird.
Any idea?