Skip to content

Commit

Permalink
Merge pull request #110 from daveray/hystrix-clj-20120219
Browse files Browse the repository at this point in the history
Cleanup and :init-fn escape hatch
  • Loading branch information
benjchristensen committed Feb 21, 2013
2 parents c3b510b + f5b7ddb commit f17a3f6
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@
A function which the same args as :run-fn that calculates a cache key for the
given args. Optional, defaults to nil, i.e. no caching.
:init-fn
A function that takes a definition map and HystrixCommand$Setter which should return
a HystrixCommand$Setter (usually the one passed in) to ultimately be passed to the
constructor of the HystrixCommand. For example,
(fn [_ setter]
(.andCommandPropertiesDefaults setter ...))
This is your escape hatch into raw Hystrix.
The com.netflix.hystrix.core/defcommand macro is a helper for defining this map and storing it
in a var. For example, here's a definition for an addition command:
Expand Down Expand Up @@ -118,6 +129,17 @@
collapser. Optional, defaults to a function returning nil, i.e. no caching.
This function should be completely free of side effects.
:init-fn
A function that takes a definition map and HystrixCollapser$Setter which should return
a HystrixCollapser$Setter (usually the one passed in) to ultimately be passed to the
constructor of the HystrixCollapser. For example,
(fn [_ setter]
(.andCollapserPropertiesDefaults setter ...))
This is your escape hatch into raw Hystrix.
The com.netflix.hystric.core/defcollapser macro is a helper for defining this map and storing it
in a callable var.
"
Expand Down Expand Up @@ -236,7 +258,8 @@
:hystrix/fallback-fn :fallback-fn
:hystrix/group-key :group-key
:hystrix/command-key :command-key
:hystrix/thread-pool-key :thread-pool-key }]
:hystrix/thread-pool-key :thread-pool-key
:hystrix/init-fn :init-fn }]
(set/rename-keys (select-keys meta-map (keys key-map)) key-map)))

(defmacro defcommand
Expand Down Expand Up @@ -300,7 +323,8 @@
(let [key-map {:hystrix/collapser-key :collapser-key
:hystrix/shared-fn :shard-fn
:hystrix/scope :scope
:hystrix/cache-key-fn :cache-key-fn }]
:hystrix/cache-key-fn :cache-key-fn
:hystrix/init-fn :init-fn }]
(set/rename-keys (select-keys meta-map (keys key-map)) key-map)))

(defn collapser
Expand Down Expand Up @@ -492,18 +516,25 @@
((required-fn :run-fn))
((optional-fn :fallback-fn))
((optional-fn :cache-key-fn))
((optional-fn :init-fn))

(update-in [:group-key] group-key)
(update-in [:command-key] command-key)
(update-in [:thread-pool-key] thread-pool-key)))

(defmethod instantiate* :command
[{:keys [group-key command-key thread-pool-key run-fn fallback-fn cache-key-fn]} & args]
(let [setter (doto (HystrixCommand$Setter/withGroupKey group-key)
; TODO other properties
[{:keys [group-key command-key thread-pool-key
run-fn fallback-fn cache-key-fn
init-fn] :as def-map} & args]
(let [setter (-> (HystrixCommand$Setter/withGroupKey group-key)
(.andCommandKey command-key)
(.andThreadPoolKey thread-pool-key))]
(proxy [HystrixCommand] [setter]
(.andThreadPoolKey thread-pool-key))
setter (if init-fn
(init-fn def-map setter)
setter)]
(when (not (instance? HystrixCommand$Setter setter))
(throw (IllegalStateException. (str ":init-fn didn't return HystrixCommand$Setter instance"))))
(proxy [HystrixCommand] [^HystrixCommand$Setter setter]
(run [] (apply run-fn args))
(getFallback [] (if fallback-fn
(apply fallback-fn args)
Expand All @@ -522,6 +553,7 @@
((required-fn :map-fn))
((optional-fn :shard-fn))
((optional-fn :cache-key-fn))
((optional-fn :init-fn))

(update-in [:collapser-key] collapser-key)
(update-in [:scope] (fnil collapser-scope HystrixCollapser$Scope/REQUEST))))
Expand All @@ -531,11 +563,17 @@
(.getArgument request))

(defmethod instantiate* :collapser
[{:keys [collapser-key scope collapse-fn map-fn shard-fn cache-key-fn]} & args]
(let [setter (doto (HystrixCollapser$Setter/withCollapserKey collapser-key)
; TODO other properties
(.andScope scope))]
(proxy [HystrixCollapser] [setter]
[{:keys [collapser-key scope
collapse-fn map-fn shard-fn cache-key-fn
init-fn] :as def-map} & args]
(let [setter (-> (HystrixCollapser$Setter/withCollapserKey collapser-key)
(.andScope scope))
setter (if init-fn
(init-fn def-map setter)
setter)]
(when (not (instance? HystrixCollapser$Setter setter))
(throw (IllegalStateException. (str ":init-fn didn't return HystrixCollapser$Setter instance"))))
(proxy [HystrixCollapser] [^HystrixCollapser$Setter setter]
(getCacheKey [] (if cache-key-fn
(apply cache-key-fn args)))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,15 @@

(use-fixtures :each request-context-fixture)

; This is an ugly hack until this Clojuresque issue is fixed:
; https://bitbucket.org/clojuresque/clojuresque/issue/4/compile-and-test-tasks-may-hang-if
; Basically just schedule a JVM shutdown once all the tests have run. This
; will utterly break if there are ever any more Clojure namespaces to test.
(defn clojuresque-shutdown-hack
; In the end, reset Hystrix so that Clojuresque will exit after running tests.
(defn hystrix-reset-fixture
[f]
(try
(f)
(finally
(future
(Thread/sleep 1000)
(println "Forcing Clojuresque test process to exit")
(System/exit 0)))))
(com.netflix.hystrix.Hystrix/reset))))

(use-fixtures :once clojuresque-shutdown-hack)
(use-fixtures :once hystrix-reset-fixture)

(deftest test-command-key
(testing "returns nil when input is nil"
Expand Down Expand Up @@ -65,6 +59,21 @@
(is (= com.netflix.hystrix.HystrixCollapser$Scope/GLOBAL
(collapser-scope :global)))))

(deftest test-normalize-command
(testing "throws if :init-fn isn't a fn"
(is (thrown-with-msg? IllegalArgumentException #"^.*init-fn.*$"
(normalize {:type :command
:run-fn +
:init-fn 999})))))

(deftest test-normalize-collapser
(testing "throws if :init-fn isn't a fn"
(is (thrown-with-msg? IllegalArgumentException #"^.*init-fn.*$"
(normalize {:type :collapser
:collapse-fn (fn [& args])
:map-fn (fn [& args])
:init-fn "foo"})))))

(deftest test-instantiate
(let [base-def {:type :command
:group-key :my-group
Expand All @@ -74,6 +83,15 @@
(let [c (instantiate (normalize base-def))]
(is (instance? com.netflix.hystrix.HystrixCommand c))))

(testing "makes a HystrixCommand and calls :init-fn"
(let [called (atom nil)
init-fn (fn [d s] (reset! called [d s]) s)
c (instantiate (normalize (assoc base-def :init-fn init-fn)))
[d s] @called]
(is (not (nil? @called)))
(is (map? d))
(is (instance? com.netflix.hystrix.HystrixCommand$Setter s))))

(testing "makes a HystrixCommand that executes :run-fn with given args"
(let [c (instantiate (normalize base-def) 99 42)]
(is (= 141 (.execute c)))))
Expand Down Expand Up @@ -159,8 +177,7 @@
(is (.isDone qc))))))

(deftest test-collapser
(#'com.netflix.hystrix.core/reset-collapser :to-upper-collapser)
; These atoms are only for testing. In real life, collapser functions should *neve*
; These atoms are only for testing. In real life, collapser functions should *never*
; have side effects.
(let [batch-calls (atom [])
map-fn-calls (atom [])
Expand Down

0 comments on commit f17a3f6

Please sign in to comment.