Running a Clojure REPL on OpenShift

Any Clojure programmer will tell you that you need a REPL (Read-Eval-Print-Loop) to develop and debug applications. Interactive development is one of the great benefits of the LISP world. It gets used rather more than shells in other languages such as Ruby and Python.

OpenShift app development is generally done locally then pushed to the cloud. But what if the deployed app doesn’t run for some reason? What you want to do is fire up a REPL and debug the app. While that should be possible in OpenShift (since you can ssh directly into your application) it’s not quite as straight-forward as you might hope.

Simply running lein repl in your project directory gives a stack trace:

Exception in thread "Thread-1" java.net.BindException: Permission denied
    at java.net.PlainSocketImpl.socketBind(Native Method)
    at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:376)
    at java.net.ServerSocket.bind(ServerSocket.java:376)
    at java.net.ServerSocket.(ServerSocket.java:237)
    at clojure.tools.nrepl.server$start_server.doInvoke(server.clj:127)
    at clojure.lang.RestFn.invoke(RestFn.java:457)
    at leiningen.repl$fn__4138.invoke(repl.clj:90)
    at clojure.lang.Delay.deref(Delay.java:33)
    at clojure.core$deref.invoke(core.clj:2080)
    at leiningen.repl$repl$fn__4172.invoke(repl.clj:175)
    at clojure.lang.AFn.applyToHelper(AFn.java:159)
    at clojure.lang.AFn.applyTo(AFn.java:151)
    at clojure.core$apply.invoke(core.clj:601)
    at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1771)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at clojure.lang.AFn.applyToHelper(AFn.java:163)
    at clojure.lang.RestFn.applyTo(RestFn.java:132)
    at clojure.core$apply.invoke(core.clj:605)
    at clojure.core$bound_fn_STAR_$fn__3984.doInvoke(core.clj:1793)
    at clojure.lang.RestFn.invoke(RestFn.java:397)
    at clojure.lang.AFn.run(AFn.java:24)
    at java.lang.Thread.run(Thread.java:722)

There are two issues: The first is that, by default, leiningen tries to bind to locahost and find a random available port. The second is that OpenShift appears not to allow multiple Java threads in the same shell.

My workaround is to put a couple of bash scripts into the $OPENSHIFT_REPO_DIR/bin/ directory along with lein. The first (which I’ve named repl-server) sets up a headless server using the $OPENSHIFT_INTERNAL_IP for the host and a high open port number (35000 in this case):

#!/bin/bash
# Script to start nrepl server with leiningen
#
export HTTP_CLIENT="wget --no-check-certificate -O"
export LEIN_REPL_PORT=35000
export LEIN_REPL_HOST=$OPENSHIFT_INTERNAL_IP
export HOME=$OPENSHIFT_DATA_DIR/home
export LEIN_JVM_OPTS=-Duser.home=$HOME

$OPENSHIFT_REPO_DIR/bin/lein repl :headless >${OPENSHIFT_DIY_LOG_DIR}/repl.log 2>&1 &
disown

Then in lein-connect I have the following:

#!/bin/bash
# Script to connect to headless nrepl server with leiningen
#
export HTTP_CLIENT="wget --no-check-certificate -O"
export LEIN_REPL_PORT=35000
export LEIN_REPL_HOST=$OPENSHIFT_INTERNAL_IP
export HOME=$OPENSHIFT_DATA_DIR/home
export LEIN_JVM_OPTS=-Duser.home=$HOME

$OPENSHIFT_REPO_DIR/bin/repl-server
$OPENSHIFT_REPO_DIR/bin/lein repl :connect $LEIN_REPL_HOST:$LEIN_REPL_PORT

And now, after making the two scripts executable:
chmod +x repl-server lein-connect
we have the expected result:

../bin/lein-connect 
REPL-y 0.1.9
Clojure 1.4.0
    Exit: Control+D or (exit) or (quit)
Commands: (user/help)
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
          (user/sourcery function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
Examples from clojuredocs.org: [clojuredocs or cdoc]
          (user/clojuredocs name-here)
          (user/clojuredocs "ns-here" "name-here")
user=>

with any server errors being recorded in ${OPENSHIFT_DIY_LOG_DIR}/repl.log.

Happy debugging :)

About these ads

About simonholgate

I'm a Clojure developer working in Liverpool, UK. I'm a sometime oceanographer and interested in democracy and Big Data.
This entry was posted in Clojure, openshift and tagged , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s