Immutant 0.10.0 Released

[Did you clean the sink?]

We're as happy as a boy with two A's to announce another alpha release of Immutant: version 0.10.0. "Another alpha? I thought you guys would be in beta by now!" We hear you. But when you ignore accomplishments, you rob yourself of some very satisfying moments. As always, view our road map here.

What is Immutant?

Immutant is an application server for Clojure. It's an integrated platform built on JBoss AS7 that aims to reduce the inherent incidental complexity in real world applications.

Where is 1.0.0.Beta1?

We've been saying for a while that the release after 0.9.0 would be 1.0.0.Beta1, and that was our intention until last week. After reviewing some of the changes going in to this release, we decided to do at least one more alpha to let you warm up to them.

These changes include:

  • The immutant.messaging/listen function is now asynchronous, so you must deref its result to make it synchronous. The only reason you might need to do this is when publishing to a topic immediately after calling listen. [IMMUTANT-217]
  • We've deprecated the immutant.cache/cache function, replacing it with two functions: create (to which cache is aliased) and lookup. We also exposed some eviction-related options. [IMMUTANT-263] [IMMUTANT-265]
  • The Pedestal project inspired us to add the immutant.web/start-servlet function, providing a means to mount any servlet (not just a Ring handler) on a web context.
  • To match conventions established by ring-server, we renamed the :reload option for immutant.web/start to :auto-reload? and better still -- we fixed it! We also honor the :reload-paths and :stacktraces? options. And since their default values are based on whether the :dev profile is active, things should "just work". [IMMUTANT-241]
  • We've exposed some of the underlying session options. You can now control the session timeout via immutant.web.session/set-session-timeout!, and control the session cookie name & other attributes via immutant.web.session/set-session-cookie-attributes!. [IMMUTANT-267]
  • Previously, we only activated the :dev profile at deployment, by default. Now we activate :dev, :user, and :base. Use Leiningen's with-profile higher order task to override. [IMMUTANT-270]

If folks are happy with the changes in this release, we'll roll out a 1.0.0.Beta1 "soon".

What else is in this release?

Other notable changes include:

  • Singleton at-style jobs now behave properly in a cluster. [IMMUTANT-146]
  • Immutant will now add any checkout dependencies to the application's effective classpath. [IMMUTANT-257]
  • When you set the :nrepl-port option, we write its value to target/nrepl-port in your project. This enables you to automatically discover the nREPL port when you set :immutant {:nrepl-port 0} in ~/.lein/profiles.clj, obviating the need to add extra config to all of your projects. Keep an eye out for a blog post on this technique soon. [IMMUTANT-255]
  • 0.10.0 has been tested with and supports Clojure 1.3.0, 1.4.0, and 1.5.1, and we've made 1.5.1 the default version for applications that don't provide a Clojure dependency. IMMUTANT-246]

Get It

The simplest way to install or upgrade to 0.10.0 is via our Leiningen plugin:

$ lein immutant install 0.10.0

See our install page for more details. Once you have it installed, take a look at our tutorials.

Note: if you plan on installing the full distributuion of 0.10.0, you will need to upgrade your lein-immutant to 0.18.1 (the slim distribution is installed by default, so this shouldn't affect many of you).

Get In Touch

If you have any questions, issues, or other feedback about Immutant, you can always find us on #immutant on freenode or our mailing lists.

Issues resolved in 0.10.0

  • [IMMUTANT-146] - singleton at jobs should behave properly in a cluster
  • [IMMUTANT-197] - Let xa/datasource accept a connection uri
  • [IMMUTANT-212] - add way to specify values that can go in a dd inside an archive at creation time
  • [IMMUTANT-217] - Have msg/listen wait for the old listener to drain its handlers
  • [IMMUTANT-227] - Give each runtime test an isolated classloader
  • [IMMUTANT-232] - Provide an HASingleon barrier per-job
  • [IMMUTANT-234] - Add --include-dependencies do deployment documentation
  • [IMMUTANT-235] - Update internal clojure version to 1.5.0
  • [IMMUTANT-236] - Stopping a shared JMS dest affects apps still using it
  • [IMMUTANT-237] - App doesn't resume after missing dependency is restored
  • [IMMUTANT-238] - document the :selector option on msg/start
  • [IMMUTANT-240] - Use clojure.tools.reader for 1.5 reader/edn features
  • [IMMUTANT-241] - Use ring-server's option names and default them according to dev mode
  • [IMMUTANT-242] - see if any of our subsystems can just become vanilla modules
  • [IMMUTANT-243] - Unscheduling a job immediately after scheduling it fails
  • [IMMUTANT-245] - Turn web/start into a macro that ensures the handler is wrapped in a var
  • [IMMUTANT-246] - Update bundled clojure to 1.5.1
  • [IMMUTANT-247] - add smoke tests for checking releases
  • [IMMUTANT-250] - clojurescript compiler fails under an ImmutantClassLoader
  • [IMMUTANT-251] - Update to leiningen-core 2.1.0
  • [IMMUTANT-252] - support loading dependencies from a private s3
  • [IMMUTANT-253] - Expose the ability to mount a servlet at a sub-context-path
  • [IMMUTANT-255] - Write nrepl port to target/repl-port (handy when port=0)
  • [IMMUTANT-257] - Treat symlinks in checkouts/ directory same way as leiningen
  • [IMMUTANT-258] - Reconfigure caches even if replication mode doesn't change
  • [IMMUTANT-259] - improperly named test ns causes stack overflow
  • [IMMUTANT-260] - support :keywords for job names in addition to strings
  • [IMMUTANT-262] - Passing records to pipeline results in invalid EDN-encoding exception
  • [IMMUTANT-263] - Expose :max-entries and :eviction options for caches
  • [IMMUTANT-264] - decode for :clojure messages shouldn't treat them as :edn
  • [IMMUTANT-265] - Deprecate cache fn in favor of two fns: create and lookup
  • [IMMUTANT-266] - listen should decode with the classloader in use when the listener was registered
  • [IMMUTANT-267] - metadata of the JSESSIONID cookie should be exposed, for setting HttpOnly, Expires etc.
  • [IMMUTANT-270] - Modify the default profile set to be [:dev, :base, :user] instead of [:dev]
  • [IMMUTANT-272] - Make an effort to eliminate duplicate session cookies
  • [IMMUTANT-273] - Update to leininingen-core 2.1.3

Overlay Screencast

I put together a quick screencast showing how to overlay the latest incremental releases of both Immutant and TorqueBox into a single app server capable of deploying both Clojure and Ruby apps.

Further, I show how those Clojure and Ruby apps can seamlessly exchange messages and share caches using the respective messaging and caching libraries from both Immutant and TorqueBox.

Enjoy!

Immutant 0.9.0 Released

We're as happy as this parrot to announce our latest release of Immutant - version 0.9.0, hopefully culminating in a 1.0.0 version mid-spring. As always, view our road map here.

What is Immutant?

Immutant is an application server for Clojure. It's an integrated platform built on JBoss AS7 that aims to reduce the inherent incidental complexity in real world applications.

What's in this release?

  • We finally tackled one of our oldest outstanding issues - support for "at-style" jobs. Because we now accept either a hash or a cron spec in our schedule function, the order of its args changed, so read the at-jobs article for details.
  • We cut our distribution size in half and doubled the number of distributions we release. So there are now two Immutant distributions available: slim and full. Both support all the Immutant clojure libraries, but only full includes the JavaEE libraries as well.
  • We exposed an :encoding option for the Immutant caches and enhanced the caching library for TorqueBox so that Ruby and Clojure applications deployed to a TorqueBox-overlaid Immutant may share Infinispan caches. Expect a blog post demonstrating this soon.
  • With this release, Immutant will now honor :ring options in your project.clj in the absence of an :init function or immutant.init namespace. So, for example, a Luminus app created using lein new luminus myapp should deploy to Immutant without any further config.
  • One other change worth noting is that we upgraded the version of JBoss AS7 we depend on. Other than bug fixes, the primary motivation was HornetQ's new use of JGroups for clustering. This should facilitate auto-scaling on OpenShift, but there is still some work to do on that front.

Next: 1.0.0.Beta1

We're hoping to begin our beta cycle with our next release. This will mark the coagulation of our API's.

Get It

The simplest way to install or upgrade to 0.9.0 is via our Leiningen plugin:

$ lein immutant install 0.9.0

See our install page for more details. Once you have it installed, take a look at our tutorials.

Get In Touch

If you have any questions, issues, or other feedback about Immutant, you can always find us on #immutant on freenode or our mailing lists.

Issues resolved in 0.9.0

  • [IMMUTANT-24] - Add 'at' support to jobs
  • [IMMUTANT-112] - Fix release job to retain build/clojars/
  • [IMMUTANT-135] - Share caches with TorqueBox apps
  • [IMMUTANT-138] - Honor :repl-options when starting nrepl servers
  • [IMMUTANT-147] - app may report it is fully deployed before initialization has finished creating web endpoints
  • [IMMUTANT-192] - Ability to define client reconnection and session reattachment options to factory
  • [IMMUTANT-203] - Non-normal priority messages can result in duplicate sends
  • [IMMUTANT-205] - *read-eval* should be false for decoding :edn and :clojure
  • [IMMUTANT-206] - Set the HTTP port via system property
  • [IMMUTANT-207] - msg/start fails for destinations that were started by another app
  • [IMMUTANT-208] - context-paths should be normalized
  • [IMMUTANT-209] - update to leiningen-core 2.0.0
  • [IMMUTANT-210] - msg/respond should set a :ttl for its messages
  • [IMMUTANT-211] - App bootstrap should be in its own module to isolate leiningen-core and its deps
  • [IMMUTANT-214] - Intermittent error invoking tests via fntest/nrepl
  • [IMMUTANT-215] - :test-paths should be on the effective classpath
  • [IMMUTANT-216] - ClojureRuntimeService gets shutdown before a Daemon's stop function is called
  • [IMMUTANT-218] - Update to the 7.2 AS line
  • [IMMUTANT-220] - we shouldn't be applying the :provided profile by default
  • [IMMUTANT-222] - Expose the encoding type used for cached items
  • [IMMUTANT-223] - Remote listeners don't ack delivery so messages remain in queue
  • [IMMUTANT-224] - Honor :ring options in lieu of any standard Immutant bootstrap options
  • [IMMUTANT-225] - Immutant rejects URLS with %2F
  • [IMMUTANT-226] - Add :init and :destroy optional callbacks to web/start
  • [IMMUTANT-228] - Create two distributions - 'slim' & 'full'
  • [IMMUTANT-231] - singleton and non-singleton jobs can't exist in the same application

At-style Jobs in Immutant

[It's about time!]

We've always supported scheduling jobs using a cron-style syntax. We've now extended that to support a finer-grained at-style syntax:

(require '[immutant.jobs :as jobs])

(jobs/schedule "my-at-job"
                #(println "I fire 4 times with a 10ms delay between each, starting in 500ms.")
                :in 500   
                :every 10 
                :repeat 3)

This functionality is available in recent incremental builds, and will be in 0.9.0, which should be released todaytomorrow.

The Details

Instead of a specification string, at-style jobs are controlled by a set of options that are passed to the immutant.jobs/schedule function, and can be mixed and matched.

We won't go through all of the permutations of the options here - you can see the details in the docs. Instead, we'll look at a few examples of usage.

If you specify a job without a cron specification or any at options, it will fire once, immediately:

(jobs/schedule "fire-now"  
               #(println "I'll fire right now, once."))

Specifying a job with just a start option (either :at or :in) will still only fire once, but at the specified time:

;; you can specify :at as a Date
(jobs/schedule "fire-later"  
               #(println "I'll fire at a-java-util-date, once.")
               :at a-java-util-date)

#inst "2013-02-27T18:29:35.222-00:00" 1361989775222

;; or as ms since the epoch
(jobs/schedule "fire-later2"  
               #(println "I'll fire at 2013-02-27T18:29:35.222, once.")
               :at 1361989775222)

;; :in signifies "ms from now"
(jobs/schedule "fire-in"  
               #(println "I'll fire in 500 ms, once.")
               :in 500)

You can control repetition of the jobs with :every, :repeat, and :until:

;; fire every 500 ms, forever
(jobs/schedule "fire-forever"  
               #(println "I'll fire every 500 ms, forever.")
               :every 500)

;; fire every 500 ms until a time in the future
(jobs/schedule "fire-for-a-while"  
               #(println "I'll fire every 500 ms, until a-java-util-date-or-ms-since-epoch.")
               :every 500
               :until a-java-util-date-or-ms-since-epoch)

;; fire 6 times, every 500 ms
(jobs/schedule "fire-repeat"  
               #(println "I'll fire 6 times (:repeat + 1) on a 500 ms interval.")
               :every 500
               :repeat 5)

;; all of the above work with an :at or :in
(jobs/schedule "fire-forever-in-a-bit"  
               #(println "I'll fire every 500 ms, forever, starting in 2500 ms.")
               :every 500
               :in 2500)

At-style jobs can be unscheduled just like cron-style jobs by passing the name to immutant.jobs/unschedule, which will be called on your behalf when the application is undeployed if you don't do it. They can also be rescheduled by calling schedule again with the same name. So "forever" in the examples really means "until undeployed, unscheduled, or rescheduled".

Can I still use the cron syntax?

Absolutely! The only change that will affect you is the order of arguments to the schedule function have changed (the old order still works for now, but is deprecated, and will be removed in 1.0.0.Beta1):

(require '[immutant.jobs :as job])
;; the deprecated signature
(jobs/schedule "old-api-cron-job"  
                   "*/5 * * * * ?"
                   #(println "I fire every 5s, forever."))

;; the new signature
(jobs/schedule "new-api-cron-job"  
                   #(println "I fire every 5s, forever.")
                   "*/5 * * * * ?")

At-style jobs are fairly new - please give it a try and let us know if you have any issues or questions.

Image credit: quinnums

A slimmer, trimmer Immutant

Immutant just got a lot lighter!

Starting with recent incremental builds, we're now publishing two distributions: slim and full. We'll also be producing these two distributions for the 0.9.0 release (out later this week), and all future releases.

What's the difference between slim and full?

The full distribution is identical to the distributions we published before this change - they contain the full JBossAS 7 application server along with the add-ons that make it Immutant. The full distribution can be used to run JavaEE applications alongside Clojure applications.

The full distribution currently weighs in at ~133 MB.

The slim distribution is a full distribution minus the JBossAS modules that aren't required for Immutant Clojure applications. The only way you'll notice this change, other than a faster install, is if you currently deploy JavaEE applications to your Immutant. The removed modules include Hibernate, OSGi, EJB, JSF, JPA, and many other TLAs. If your application needs any of those modules (or any of the other modules we remove), you'll want to use the full distribution.

The slim distribution currently weighs in at ~66 MB.

How do I get one or the other?

If you are using the Leiningen Immutant plugin, a call to lein immutant install will install the slim version of the latest incremental build. To get the full distribution, you'll need to update to version 0.16.0 or newer of the plugin, and pass the --full option to the install subtask: lein immutant install --full. Installing a versioned release with the plugin will behave the same way for 0.9.0 or newer (once 0.9.0 is released).

If you prefer to manually download the zip distributions, you can find links to them on the incremental and release pages.

Since the slim distribution is brand new, it may have issues - please give it a try and let us know if you find any.