immutant

37
Norman Richards [email protected] Immutant

Upload: norman-richards

Post on 15-Jan-2015

947 views

Category:

Technology


0 download

DESCRIPTION

Austin Clojure Meetup (8/12/2013) Updated for Dalls Clojure Meetup (8/22/2013) demo code: https://github.com/orb/pi-game

TRANSCRIPT

Page 2: Immutant

Clojure Web Development

$ lein new compojure myapp

$ lein ring server

Congratulations, you now have a Clojure web application listening on port 3000!

Page 3: Immutant

Immutant

What about?

? database

? messaging

? scheduling

? clustering

? production

Page 4: Immutant

Immutant

+ Based on JBoss AS 7

+ Makes use of Clojure standards (ring)

+ Production-ready stack out of the box

Page 5: Immutant

Setup

+ add immutant plugin to ~/.lein/profiles.clj

{:user {:plugins [[lein-immutant "1.0.0"]]}

Page 6: Immutant

Setup

$ lein immutant installDownloading http://repository-projectodd.forge.cloudbees.com/release/org/immutant/immutant-dist/1.0.0/immutant-dist-1.0.0-slim.zipdone! Extracting /var/folders/jw/p379vgcn62q51q4_95xm1v6m0000gp/T/lein-immutant-8041099c-b2c5-4342-ac81-9e3986dfcbd2/immutant-dist-1.0.0-slim.zipExtracted /Users/norman/.immutant/releases/immutant-1.0.0-slimLinking /Users/norman/.immutant/current to /Users/norman/.immutant/releases/immutant-1.0.0-slimThe following versions of Immutant are installed to /Users/norman/.immutant(* is currently active via /Users/norman/.immutant/current):

* 1.0.0 (type: slim)

Page 7: Immutant

Setup

$ lein immutant deployDeployed myapp to /Users/norman/.immutant/current/jboss/standalone/deployments/myapp.clj

Page 8: Immutant

Setup

$ lein immutant runStarting Immutant: /Users/norman/.immutant/current/jboss/bin/standalone.sh=========================================================================

JBoss Bootstrap Environment

JBOSS_HOME: /Users/norman/.immutant/current/jboss

JAVA: java

JAVA_OPTS: -server -XX:+UseCompressedOops -Xms64m -Xmx512m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -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.CR116:13:02,294 INFO [org.jboss.msc] (main) JBoss MSC version 1.0.4.GA16:13:02,344 INFO [org.jboss.as] (MSC service thread 1-6) JBAS015899: JBoss AS 7.2.x.slim.incremental.6 "Janus" starting ... ... ...16:13:12,534 INFO [org.jboss.as] (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)

Page 9: Immutant

Setup

$ lein immutant run --clustered ... ...16:17:44,573 INFO [org.jboss.as] (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)

Page 10: Immutant

Housekeeping

$ lein immutant undeployUndeployed /Users/norman/.immutant/releases/immutant-1.0.0-slim/jboss/standalone/deployments/myapp.clj

Page 11: Immutant

Housekeeping

$ lein immutant env immutant-home: /Users/norman/.immutant/current jboss-home: /Users/norman/.immutant/current/jboss

Page 12: Immutant

Housekeeping

$ lein immutant listThe following applications are deployed to /Users/norman/.immutant/current: blue-app.clj (status: deployed) red-app.clj (status: deployed)

Page 13: Immutant

Modules+ immutant.web+ immutant.xa+ immutant.cache+ immutant.messaging+ immutant.jobs+ immutant.daemons

Page 14: Immutant

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 "/"})

Page 15: Immutant

immutant.web

(ns immutant.init  (:require [somewebapp.handler :as handler]            [immutant.web :as web]))

(web/start "/" handler/app)

Page 16: Immutant

immutant.web

/context-prefix /handler-path /app-path

From the deployment

From immutant init From your application

Page 17: Immutant

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}}))))

Page 18: Immutant

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

Page 19: Immutant

immutant.xa

(defonce my-datasource (xa/datasource "mydb" {:adapter "postgres" :host "33.33.33.50" :username "db-user" :password "db-password" :database "my-awesome-db"}))

(def db-spec {:datasource my-datasource})

Page 20: Immutant

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"})

Page 21: Immutant

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))))

Page 22: Immutant

+ 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

Page 23: Immutant

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))

Page 24: Immutant

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))

Page 25: Immutant

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

Page 26: Immutant

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)

Page 27: Immutant

immutant.messaging

+ Priority, expiration, persistence, properties+ Easy to toss around Clojure data structures+ Pipelines are very cool

+ Topics and queues

Page 28: Immutant

immutant.jobs(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)))))

Page 29: Immutant

immutant.jobs

(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))

Page 30: Immutant

+ 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

immutant.jobs

Page 31: Immutant

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)

Page 32: Immutant

immutant.daemons

+ Can be long running+ Singleton processes can be reliably setup

+ Manage application-specific services

Page 33: Immutant

The PI Game

πhttps://github.com/orb/pi-game

Page 34: Immutant

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

Page 35: Immutant

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

Page 36: Immutant

• 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

Page 37: Immutant

• 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