public
Last active

  • Download Gist
catch.cljs
Clojure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
(ns blog.errors.core
(:require-macros
[cljs.core.async.macros :refer [go]]
[blog.utils.macros :refer [<?]])
(:require
[cljs.core.async :refer [>! <! chan close!]]))
 
;; convert Node.js async function into a something
;; that returns a value or error on a channel
(defn run-task [f & args]
(let [out (chan)
cb (fn [err & results]
(go (if err
(>! out err)
(>! out results))
(close! out)))]
(apply f (concat args [cb]))
out))
 
(def fs (js/require "fs"))
 
;; BOOM!!! we can convert async errors into exceptions
(go (try
(let [x (<? (run-task (.-readFile fs) "foo.txt" "utf8"))]
(.log js/console "Success" x))
(catch js/Error e
(.log js/console "Oops" e))))
core.cljs
Clojure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
(ns blog.errors.core
(:require-macros
[cljs.core.async.macros :refer [go]])
(:require
[cljs.core.async :refer [>! <! chan close!]]))
 
(defn error? [x]
(instance? js/Error x))
 
(defn run-task [f & args]
(let [out (chan)
cb (fn [err & results]
(go (if err
(>! out err)
(>! out results))
(close! out)))]
(apply f (concat args [cb]))
out))
 
;; wrap a task to run in a thunk so a supervisor can call it
(defn task [& args]
(fn [] (apply run-task args)))
 
;; a policy so a supervisor knows to retry a task
(defprotocol IPolicy
(-retry? [this err attempts]))
 
;; retry a task up to N times policy
(defn maxtries [n]
(reify
IPolicy
(-retry? [_ err attempts]
(< attempts n))))
 
;; take a task to run and a policy for retries
(defn supervisor [task policy]
(go (loop [attempts 0 err nil]
(if-not (-retry? policy err attempts)
err
(let [v (<! (task))]
(if (error? v)
(let [attempts (inc attempts)]
(do (.log js/console "Attempt" attempts)
(recur attempts v)))
v))))))
 
(def fs (js/require "fs"))
 
;; go macro lets us write straight line code even though supervisor
;; implements sophisticated async behavior
(go (let [result (<! (supervisor
(task (.-readFile fs) "foo.txt" "utf8")
(maxtries 3)))]
(if-not (error? result)
(.log js/console (.split (first result) "\n"))
(.log js/console result))))

dat core.async 0_o

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.