Discrepancies from REPL dev to Prod

It is a serious damage to the benefit of having a REPL if things behave quite differently between dev and prod (“prod” being what comes out of lein uberjar). Building web apps I see this happening from time to time; for example, right now the two problems I’m dealing with are:

  1. csrf-protection working in dev but not with java -jar operations
  2. My server providing images (just one, to be precise: a header image) which is part of the package and is visible in REPL but replies with a 500 error in java -jar operations

While it would really be great if someone here had resolved either of those issues before, my point is really the more general one: what do you do when the awesome power of REPL-driven development is undermined by this lack of reliability that Prod will behave as dev does?

No idea about 1) but I suspect 2) is due to how you’re serving files in your web app (treating them as local files instead of resources on the classpath I expect).

A good way to verify this is build the uberjar locally and start it up with a Socket REPL so you can do RDD inside the running JAR (assuming you have dev tooling that is compatible with a Socket REPL).

1 Like

Apparently one solution is to come back tomorrow, possibly restarting the computer… 1 just went away with no action taken. Which tells me it was probably cache and/or user error.

Thanks for the idea; I’ve never actually used an open socket in a jar, but that’s a great idea.

No need to limit yourself to a Socket REPL. We happily run nRepl in production (behind an SSH tunnel of course) so that we can diagnose things like that easily.

1 Like

What’s the difference between a socket REPL and nREPL?

Socket REPL is built-in to Clojure, and you can start it via just a JVM property. Not many editor tools support it though (inferior-Clojure in emacs, Chlorine in Atom)

nRepl is a third-party library, which is a de-facto standard, supported by CIDER, Calva in VSCode etc.

We don’t use nREPL at all. We used to run nREPL in production but we didn’t like having that “development” dependency in our production code (and we originally had it with the full CIDER middleware stack!).

Both myself and my teammate (hiredman/Kevin Downey) now use simple Socket REPLs, which can be started for any Clojure process just by adding a JVM option, with no additional dependencies at all. Our editor tooling supports Socket REPL, so we can ssh tunnel to a server and connect our editor directly to the live, running process, and have the full toolkit on hand that we already use locally for dev work to debug our production process and, if necessary, apply a live patch.

3 Likes

Having the full toolkit is the key. It’s awesome :slight_smile:

I agree that having a “dev” dependency is not ideal, but in practice I haven’t seen any issues (and I do include the whole CIDER middleware too).

1 Like

That’s why I’m very excited to see what happens with: https://github.com/nrepl/nrepl/issues/96

Best of both world!

@Webdev_Tory,

I believe I was in a situation similar to yours a while back:

  1. No experienced Clojurians to rely on
  2. No large existing system
  3. I’d like a production REPL system

I converged on building a deps.edn app that just ran the code with a clojure -m my.app.main, packaged with Docker, and starts an nREPL server on a different port. By running the app the same way in dev and prod, I simply don’t have to account for Uberjar differences – except for running code inside and outside of Docker.

As I see it, the primary utility of packaging your app as an Uberjar is to be able to interact with the Java ecosystem, for instance if your organization already has tooling in place to put Java code in production.

I’m about what you end up choosing to do!