Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.


Austin Clojure Meetup (8/12/2013)
Updated for Dalls Clojure Meetup (8/22/2013)

demo code:

  • Be the first to comment


  1. 1. Norman Richards orb@nostacktrace.comImmutant
  2. 2. Clojure Web Development $ lein new compojure myapp $ lein ring server Congratulations, you now have a Clojure web application listening on port 3000!
  3. 3. Immutant What about? ? database ? messaging ? scheduling ? clustering ? production
  4. 4. Immutant + Based on JBoss AS 7 + Makes use of Clojure standards (ring) + Production-ready stack out of the box
  5. 5. Setup + add immutant plugin to ~/.lein/profiles.clj {:user {:plugins [[lein-immutant "1.0.0"]]}
  6. 6. Setup $ lein immutant install Downloading done! Extracting /var/folders/jw/p379vgcn62q51q4_95xm1v6m0000gp/T/lein-immutant-8041099c-b2c5-4342-ac81-9e3986dfcbd2/ Extracted /Users/norman/.immutant/releases/immutant-1.0.0-slim Linking /Users/norman/.immutant/current to /Users/norman/.immutant/releases/immutant-1.0.0-slim The following versions of Immutant are installed to /Users/norman/.immutant (* is currently active via /Users/norman/.immutant/current): * 1.0.0 (type: slim)
  7. 7. Setup $ lein immutant deploy Deployed myapp to /Users/norman/.immutant/current/jboss/standalone/deployments/myapp.clj
  8. 8. Setup $ lein immutant run Starting Immutant: /Users/norman/.immutant/current/jboss/bin/ ========================================================================= JBoss Bootstrap Environment JBOSS_HOME: /Users/norman/.immutant/current/jboss JAVA: java JAVA_OPTS: -server -XX:+UseCompressedOops -Xms64m -Xmx512m -XX:MaxPermSize=256m - Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true ========================================================================= 16:13:01,823 INFO [org.jboss.modules] (main) JBoss Modules version 1.2.0.CR1 16:13:02,294 INFO [org.jboss.msc] (main) JBoss MSC version 1.0.4.GA 16:13:02,344 INFO [] (MSC service thread 1-6) JBAS015899: JBoss AS 7.2.x.slim.incremental.6 "Janus" starting ... ... ... 16:13:12,534 INFO [] (Controller Boot Thread) JBAS015874: JBoss AS 7.2.x.slim.incremental.6 "Janus" started in 10969ms - Started 128 of 175 services (46 services are passive or on-demand)
  9. 9. Setup $ lein immutant run --clustered ... ... 16:17:44,573 INFO [] (Controller Boot Thread) JBAS015874: JBoss AS 7.2.x.slim.incremental.6 "Janus" started in 10170ms - Started 130 of 223 services (92 services are passive or on-demand)
  10. 10. Housekeeping $ lein immutant undeploy Undeployed /Users/norman/.immutant/releases/immutant-1.0.0-slim/jboss/standalone/deployments/myapp.clj
  11. 11. Housekeeping $ lein immutant env immutant-home: /Users/norman/.immutant/current jboss-home: /Users/norman/.immutant/current/jboss
  12. 12. Housekeeping $ lein immutant list The following applications are deployed to /Users/norman/.immutant/current: blue-app.clj (status: deployed) red-app.clj (status: deployed)
  13. 13. Modules + immutant.web + immutant.xa + immutant.cache + immutant.messaging + + immutant.daemons
  14. 14. immutant.web (defproject somewebapp "0.1.0-SNAPSHOT" ;; ... :plugins [[lein-ring "0.8.5"]] :ring {:handler somewebapp.handler/app}) (defproject somewebapp "0.1.0-SNAPSHOT" ;; ... :immutant {:nrepl-port 0 :context-path "/"})
  15. 15. immutant.web (ns immutant.init   (:require [somewebapp.handler :as handler]             [immutant.web :as web])) (web/start "/" handler/app)
  16. 16. immutant.web /context-prefix /handler-path /app-path From the deployment From immutant init From your application
  17. 17. immutant.web (def app (-> app-routes ;; additional handlers handler/site)) (def app (let [store (immutant.web.session/servlet-store)] (-> app-routes ;; additional handlers (handler/site {:session {:store store}}))))
  18. 18. immutant.web + works with non-ring apps (eg. Pedestal) + control over virtual hosts and context paths + can dynamically start/stop endpoints + minimal changes to your code, framework agnostic
  19. 19. immutant.xa (defonce my-datasource (xa/datasource "mydb" {:adapter "postgres" :host "" :username "db-user" :password "db-password" :database "my-awesome-db"})) (def db-spec {:datasource my-datasource})
  20. 20. immutant.xa (jdbc/with-connection db-spec (jdbc/do-commands "CREATE TABLE widgets ( name VARCHAR NOT NULL PRIMARY KEY, count VARCHAR NOT NULL DEFAULT 0);")) (jdbc/with-connection db-spec (korma.core/select :widgets)) (def db-spec {:name "java:jboss/datasources/SomeExternalDS"})
  21. 21. immutant.xa (defn new-widget [name number] (let [widget {:name name :count number}] (xa/transaction (jdbc/with-connection db-spec (korma/insert :widgets (korma/values widget))) (msg/publish "/queue/widgets" widget))))
  22. 22. + integrates well with Clojure database things + XA transactions are tricky and hard to test + Most apps use many non-XA resources + database config can be external and shared immutant.xa + All the immutant services are XA
  23. 23. immutant.cache (def game-cache (cache/create "game" :persist true :sync true))   (def job-cache (cache/create "job-status" :ttl 10 :idle 1 :units :minutes))
  24. 24. immutant.cache (defn add-points [player points] (let [current-score (get game-cache player 0) new-score (+ current-score points)] (cache/put game-cache player new-score) new-score))
  25. 25. immutant.cache + Really easy to use + Interface isn’t very Clojure-like, needs abstraction + Should a data grid be deployed along side app? + Infinispan does much more than caching
  26. 26. immutant.messaging (msg/start "/queue/orders") (msg/start "/topic/new-widget")   (defn process-order [order] (println "processing" order) (msg/publish "/topic/new-widget" {:widget order}))   (defonce widgets (atom [])) (defn cache-widget [widget] (swap! widgets #(conj % widget)) (println "I have" (count @widgets) "widgets"))   (msg/listen "/queue/orders" process-order) (msg/listen "/topic/new-widget" cache-widget)
  27. 27. immutant.messaging + Priority, expiration, persistence, properties + Easy to toss around Clojure data structures + Pipelines are very cool + Topics and queues
  28. 28. (defonce heartbeat (atom nil))   (defn send-heartbeat [] (riemann/send-event {:service "heartbeat" :state "ok" :metric 1}))   (defn heartbeat-thread [every-n-sec] (while true (send-heartbeat) (Thread/sleep (* 1000 every-n-sec))))   (defn start-heartbeat [] (swap! heartbeat (fn [heartbeat] (or heartbeat (doto (Thread. #(heartbeat-thread 10)) .start)))))   (defn stop-heartbeat [] (swap! heartbeat (fn [heartbeat] (when heartbeat (.stop heartbeat)))))
  29. 29. (defn send-heartbeat [] (riemann/send-event {:service "heartbeat" :state "ok" :metric 1}))   (defn start-heartbeat [] (jobs/schedule :heartbeat send-heartbeat :every 10000))   (defn stop-heartbeat [] (jobs/unschedule :heartbeat))
  30. 30. + Also supports CRON-like scheduling syntax + Can be used for ad-hoc jobs + Not easy to see what jobs are scheduled/running + Jobs can be on all nodes or just one
  31. 31. immutant.daemons (defonce listener (atom nil)) (defn start-listener [] (swap! listener (fn [listener] (msg/listen "/queue/guesses" play/handle-guess))))   (defn stop-listener [] (swap! listener (fn [listener] (when listener (msg/unlisten listener)))))   (daemon/daemonize "guess-listener" start-listener stop-listener :singleton true)
  32. 32. immutant.daemons + Can be long running + Singleton processes can be reliably setup + Manage application-specific services
  33. 33. The PI Game π
  34. 34. PI Game Demo + EDN api to get state and send actions + Game state saved in persistent cache + Clojurescript front end, Clojure back end + + + Player actions are sent to guess queue Singleton daemon creates one listener per cluster Demo uses two immutant nodes with nginx in front
  35. 35. But... • Works out of the box • It’s good Clojure - not “Clojure 2 Enterprise Edition” • Best solution for multiple applications • Best solution when you want to work with Java or Ruby apps • JBoss is production tested • Responsive dev team • Are these the services you would have chosen? • It’s one big blob, not lots of composable blocks • Does it fit your application architecture? • Does it fit your ops strategy? Yes
  36. 36. • App was ring/jetty - using our own custom startup • Wanted to split our APIs out and modularize app instead of deploying as a monolithic app • Wanted to be able to support rolling updates across nodes • Liked the idea of being able to bring mature clustering, caching and messaging into the app almost for free Immutant at Threatgrid
  37. 37. • Transition to Immutant was very fast and required only minor changes to our customized startup code • We ran into a few small issues, but the Immutant dev team had almost immediate fixes/workarounds. • Transitional codebase still supports running outside Immutant, so we haven’t been able to leverage some features • Ops team strongly prefers individual services that can be managed independently - Immutant is one big ball • Our web nodes and data nodes scale separately - Immutant seems to prefer a more homogenous deployment • Immutant a la carte would really hit a sweet spot And.... we’re still deciding