Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Concurrency’s Next Frontier: Actor Systems in Clojure

Andrei Ursan
February 20, 2016

Concurrency’s Next Frontier: Actor Systems in Clojure

Wunderlist, with millions of active users, continues to grow, bending its realtime sync technology to the limits. This pushed them to rethink and experiment with different architectural approaches. As a result Akka’s Actor System become a key component of theirs realtime architecture. However Actor Systems are not popular in the Clojure Ecosystem. In this talk Andrei will cover what they learned from using Actor Systems, what are their advantages and how to use them in Clojure.

Andrei Ursan

February 20, 2016
Tweet

More Decks by Andrei Ursan

Other Decks in Programming

Transcript

  1. WHOAMI (def me {:name "Andrei Ursan" :twitter "@andreiursan" :work "Software

    Engineer, @Microsoft" :builds "Wunderlist" :tags #{:polyglot :microservices :scalability}}) @andreiursan 2
  2. Agenda • How Wunderlist uses Actors. • How to use

    Actors in Clojure. @andreiursan 3
  3. Akka • a toolkit for distributed applica.ons • emphasises actor

    based concurrency • actors are async • part of Scala’s standard library @andreiursan 9
  4. Wunderlist and Actors • For each socket connec.on an actor

    is created. • The WebSocketActor creates: • an actor for h9p requests @andreiursan 11
  5. Wunderlist and Actors • For each socket connec.on an actor

    is created. • The WebSocketActor creates: • an actor for h9p requests • an actor that listens for user events @andreiursan 12
  6. Wunderlist and Actors • For each socket connec.on an actor

    is created. • The WebSocketActor creates: • an actor for h9p requests • an actor that listens for user events • User events are distributed via RabbitMQ @andreiursan 13
  7. Actors in Clojure • Akka wrappers • not complete •

    not maintained • puniverse/pulsar • Idioma4c Clojure wrapper around quasar @andreiursan 16
  8. Pulsar • like erlang • lightweight processes (a.k.a. fibers) •

    actors can block • gen-servers • supervisors • core.async like channels @andreiursan 20
  9. (defactor actor-name [] (loop [] (receive :pattern-one (do (action-one) (recur))

    [:pattern-two msg] (action-two msg) :pattern-three (action-three)))) @andreiursan 27
  10. (defactor actor-name [] (loop [] (receive :pattern-one (receive [:pattern-two msg]

    (action-one-two msg)) :pattern-three (action-three)))) @andreiursan 28
  11. (defactor inc-actor [n] (loop [n n] (receive :inc (recur (inc

    n)) [:inc number] (recur (+ n number)) :print (println n)))) ; @andreiursan 29
  12. (defactor inc-actor [n] (loop [n n] (receive :inc (recur (inc

    n)) [:inc number] (recur (+ n number)) :print (println n)))) (register! :my-inc (spawn inc-actor 5)) (! :my-inc :inc) (! :my-inc [:inc 4]) (! :my-inc :print) ; => 10 @andreiursan 30
  13. (require '[co.paralleluniverse.pulsar.actors :refer :all]) • defactor defines a template for

    an actor • receive returns the next message from the mailbox • spawn launches an actor • ! sends a message to an actor • self evaluated in an actor, returns its address @andreiursan 31
  14. (require `[co.paralleluniverse.fiber.httpkit.client :as client]) (defactor get-link [parent link] (let [response

    (client/get link)] (! parent [:link-status {link (:status response)}]))) (defactor check-links [links] (doseq [link links] (spawn get-link @self link)) ; … @andreiursan 34
  15. (require `[co.paralleluniverse.fiber.httpkit.client :as client]) (defactor get-link [parent link] (let [response

    (client/get link)] (! parent [:link-status {link (:status response)}]))) (defactor check-links [links] (doseq [link links] (spawn get-link @self link)) (loop [data {}] (receive [:link-status link-status] (do (recur (merge data link-status))) @andreiursan 35
  16. (defactor get-link [parent link] (let [response (client/get link)] (! parent

    [:link-status {link (:status response)}]))) (defactor check-links [links] (doseq [link links] (spawn get-link @self link)) (loop [data {}] (receive [:link-status link-status (do (recur (merge data link-status)))] :print (do (pprint data) (recur data)) :stop (println "Good Bye!")))) (def links ["http://bobkonf.de/" "http://clojured.de"]) (register! :checker (spawn check-links links)) (! :checker :print) ;=> {"http://bobkonf.de/" 200, "http://clojured.de" 200])) @andreiursan 36
  17. (defactor dangerous-dave [] (receive) (throw (Exception. "Boom! Boom!"))) (def sup

    (spawn (supervisor :one-for-one #()))) ; :escalate :one-for-one :all-for-one or :rest-for-one @andreiursan 38
  18. (defactor dangerous-dave [] (receive) (throw (Exception. "Boom! Boom!"))) (def sup

    (spawn (supervisor :one-for-one #()))) (add-child! sup "dave-id" :permanent 3 1 :sec 10 dangerous-dave) ; [sup id mode max-restarts duration unit ; shutdown-deadline-millis actor-fn & actor-args] ; mode: :permanent :transient or :temporary. @andreiursan 39
  19. (defactor dangerous-dave [] (receive) (throw (Exception. "Boom! Boom!"))) (def sup

    (spawn (supervisor :one-for-one #()))) (add-child! sup "dave-id" :permanent 3 1 :sec 10 dangerous-dave) (def dave (get-child sup "dave-id")) (! dave :foo) ; You cannot kill me! @andreiursan 40
  20. (fact "Test actor matching receive" (let [actor (spawn (actor []

    (receive :abc "yes!" :else "oy")))] (! actor :abc) (join actor)) => "yes!") @andreiursan 42
  21. (fact "When matching receive and timeout then run :after clause"

    (let [actor (spawn (actor [] (receive [:foo] nil :else (println "got it!") :after 30 :timeout)))] (Thread/sleep 150) (! actor 1) (join actor)) => :timeout) @andreiursan 43
  22. Final Thoughts • actor model can be a powerful tool

    • simple resource access • fits well for event-driven/async problems • tool diversity for the Clojure Ecosystem is GOOD. @andreiursan 44
  23. History • 1973, Carl Hewi, et al.: A universal modular

    ACTOR formalism for ar<ficial intelligence • 1986, Gul Agha et. al.: Actors • 1995, Ericson: first commercial use of Erlang/OTP • 2006, Erlang/OTP SMP (adds Symmetrical Mul<Processing) • 2009, Jonas Bonér: crea<on of Akka @andreiursan 45
  24. Resources • The Actor Model (video) • What are fibers

    and why should you care? • Farewell to Asynchronous Code • Pulsar Docs • Web Actors: Comsat • Distributed Actors in Java and Clojure • Galaxy part 1, part 2, part 3 @andreiursan 46