Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure hot code swapping for uberjars/.classes

Tags:

clojure

osgi

I want to have hot code swapping between project updates, but I haven't found any information about how to load .class files dynamically. More specifically, I want something like that:

  1. Make lein uberjar, obtain some-client-0.0.0-standalone.jar.
  2. Run it with java -jar some-client-0.0.0-standalone.jar.
  3. Make changes to project. Obtain new program version, some-client-0.0.1-standalone.jar, copy it to some-client-0.0.0-standalone.jar directory.
  4. Client receive sequence of commands needed to update to new version.
  5. (optional) Updates resources. Resources from old jar are no longer used.
  6. (optional) some-client-0.0.0-standalone.jar can be deleted now.
like image 797
desudesudesu Avatar asked Feb 28 '13 21:02

desudesudesu


2 Answers

Plug-in framework approach

You've stated you want to have hot code swapping, but what you actually need is loosely coupled modules and ability to do resolve in run-time. Frankly speaking any plug-in framework may help, including mature OSGi (will be covered below).

enter image description here

Since you are doing some kind of PoC I suggest to review the following example:

  1. you have a meta application with some extension points (metaphor explanation) defined
  2. functionality to be upgraded or replaced will be implemented as a loosely coupled modules (plug-ins)
  3. meta application performs resolve by request or automatically in order to find updated "functionality" (according to defined extension points)

Having that define simlle upgrade scenario can be proposed:

  1. user uses an application
  2. user installs (copies) a JAR (other type of bundle) with new implementation of one or several extension points
  3. user triggers global system resolve or system scans for new updates or system performs resolve every tine user tries to access some piece of functionality

In such a way meta application will be able to provide a new or updated functionality without restart. So you can:

  1. try use some simple java plug-in framework (like, for example, Java Simple Plugin Framework. 5 minutes and it works. No XML. This approach seems to be a little bit ugly
  2. use dynamic nature of clojure, as was suggested here

You can also review and adopt Waterfront (Clojure based editor for Clojure) findings (it might be needed to enhance lifecycle management, etc)

  • check the Modular composition/plugin architecture thread
  • look through the code waterfront on SourceForge

In terms of implementation, Waterfront is based on the context pattern. It allows event handlers to communicate in a functional (side-effect free) manner. On top of this there is a plugin-loader mechanism which loads the plugins that are specified in Waterfront's configuration file. This means that functionality can be easily added or removed (extremely useful when debugging!).

OSGI approach

As was suggested OSGi seems to be a good way to solve your problem. Please also note OSGi is good, mature and provides a lot stuff out of the box, but it is also somewhat complex:

enter image description here

BTW, OSGi is a long-term goal for the clojure community. You can check Clojure Todo:

> better modularization for OSGi etc 
>  * names
>  * no single namespace pool
>  * namespaces found via classes, thus tracks classloader and modules 
>  * deal with import proxying a la Class.forName stack walk?

There are some solutions already available:

  1. clojure-osgi-utils
  2. clojure.osgi

Second project provides Producer-Consumer example using clojure and OSGi:

  • producer service
  • consumer service

Happy coding.

like image 78
Renat Gilmanov Avatar answered Nov 13 '22 11:11

Renat Gilmanov


For reloading at runtime strictly from jar files you may need to look into OSGi class loaders. For Clojure code you could start nrepl in your client that listens on a local port and then when you want to reload the code you connect to that port and make a call to load-file

like image 33
Arthur Ulfeldt Avatar answered Nov 13 '22 10:11

Arthur Ulfeldt