Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best Practice Way to Embed NREPL in Clojure Server

Tags:

clojure

nrepl

I've just started development of a service in Clojure. I'm a little lost in how to approach server shutdown.

I'm using Clojure 1.5.1. For logging, I'm using Timbre 1.5.3. I want to embed NREPL into my server for hot code deployment.

This is my core.clj file. Core is my main and I'm using the app shell that "lein new app" generates.

(ns extenium.core
  (:require [taoensso.timbre :as t]
            [clojure.tools.nrepl.server :as nrs])
  (:gen-class))

(def nrepl-server)

(defn start-nrepl-server []
  (t/info "Starting nrepl server on port 8628")
  (alter-var-root #'nrepl-server
                  (constantly
                   (nrs/start-server :port 8628)))
  (t/info "Started nrepl server"))

(defn stop-nrepl-server []
  (t/info "Stopping nrepl server")
  (nrs/stop-server nrepl-server)
  (t/info "Stopped nrepl server"))

(defn start []
  (alter-var-root #'*read-eval*
                  (constantly
                   false))
  (start-nrepl-server))

(defn stop []
  (stop-nrepl-server))

(defn -main [& args]
  (start))

When I "lein run" the nrepl-server starts as expected, with info messages going to the Terminal. I then connect with "nrepl" from Emacs. No problem. From Emacs I execute "(extenium.core/stop)". At that point, I get the "Stopping nrepl server" message on Emacs (meaning that stdout was redirected to the client). The connection closes (as expected) and I never see the "Stopped nrepl server" message. Fine.

I look at the Terminal and I don't see the "Stopping..." or "Stopped..." messages. Instead, I get the following exception:

Exception in thread "nREPL-worker-0" java.lang.Error: java.net.SocketException: Socket closed

Ideally, I want the following:

  1. To be able to initiate shutdown from an NREPL client. Gracefully close all NREPL client connections without exception. Shutdown with the logging messages directed towards the Terminal (or eventually, a rotating log file).
  2. For the duration of the NREPL connection, clone the logging output to both the server (Terminal or log) and to the NREPL output.
  3. Capture information about incoming NREPL connections, name them, and log connect and disconnect activity.
  4. Eventually, authenticate incoming NREPL connections.
  5. Even later, authorize them for actions they perform.
like image 592
jennykwan Avatar asked Apr 19 '13 12:04

jennykwan


1 Answers

Disclaimer: I haven't done this, but it seems interesting.

Per the README, specifically the section "Why nREPL?" you should be able to implement 2 - 4 by implementing your own custom transport, perhaps merely extending one of the out-of-the-box ones.

Stopping the server gracefully may entail extending the socket transport. What you are describing as "graceful shutdown" sounds like implementation of a "Logout" protocol.

Authorizing actions they perform seems less straightforward. It looks like you would need to implement a custom Handler, perhaps again wrapping the default-handler with the authorization code.

Good luck!

like image 124
noahlz Avatar answered Nov 20 '22 18:11

noahlz