Skip to content

Commit f17a3f6

Browse files
Merge pull request Netflix#110 from daveray/hystrix-clj-20120219
Cleanup and :init-fn escape hatch
2 parents c3b510b + f5b7ddb commit f17a3f6

File tree

2 files changed

+79
-24
lines changed
  • hystrix-contrib/hystrix-clj/src

2 files changed

+79
-24
lines changed

hystrix-contrib/hystrix-clj/src/main/clojure/com/netflix/hystrix/core.clj

+50-12
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@
4949
A function which the same args as :run-fn that calculates a cache key for the
5050
given args. Optional, defaults to nil, i.e. no caching.
5151
52+
:init-fn
53+
54+
A function that takes a definition map and HystrixCommand$Setter which should return
55+
a HystrixCommand$Setter (usually the one passed in) to ultimately be passed to the
56+
constructor of the HystrixCommand. For example,
57+
58+
(fn [_ setter]
59+
(.andCommandPropertiesDefaults setter ...))
60+
61+
This is your escape hatch into raw Hystrix.
62+
5263
The com.netflix.hystrix.core/defcommand macro is a helper for defining this map and storing it
5364
in a var. For example, here's a definition for an addition command:
5465
@@ -118,6 +129,17 @@
118129
collapser. Optional, defaults to a function returning nil, i.e. no caching.
119130
This function should be completely free of side effects.
120131
132+
:init-fn
133+
134+
A function that takes a definition map and HystrixCollapser$Setter which should return
135+
a HystrixCollapser$Setter (usually the one passed in) to ultimately be passed to the
136+
constructor of the HystrixCollapser. For example,
137+
138+
(fn [_ setter]
139+
(.andCollapserPropertiesDefaults setter ...))
140+
141+
This is your escape hatch into raw Hystrix.
142+
121143
The com.netflix.hystric.core/defcollapser macro is a helper for defining this map and storing it
122144
in a callable var.
123145
"
@@ -236,7 +258,8 @@
236258
:hystrix/fallback-fn :fallback-fn
237259
:hystrix/group-key :group-key
238260
:hystrix/command-key :command-key
239-
:hystrix/thread-pool-key :thread-pool-key }]
261+
:hystrix/thread-pool-key :thread-pool-key
262+
:hystrix/init-fn :init-fn }]
240263
(set/rename-keys (select-keys meta-map (keys key-map)) key-map)))
241264

242265
(defmacro defcommand
@@ -300,7 +323,8 @@
300323
(let [key-map {:hystrix/collapser-key :collapser-key
301324
:hystrix/shared-fn :shard-fn
302325
:hystrix/scope :scope
303-
:hystrix/cache-key-fn :cache-key-fn }]
326+
:hystrix/cache-key-fn :cache-key-fn
327+
:hystrix/init-fn :init-fn }]
304328
(set/rename-keys (select-keys meta-map (keys key-map)) key-map)))
305329

306330
(defn collapser
@@ -492,18 +516,25 @@
492516
((required-fn :run-fn))
493517
((optional-fn :fallback-fn))
494518
((optional-fn :cache-key-fn))
519+
((optional-fn :init-fn))
495520

496521
(update-in [:group-key] group-key)
497522
(update-in [:command-key] command-key)
498523
(update-in [:thread-pool-key] thread-pool-key)))
499524

500525
(defmethod instantiate* :command
501-
[{:keys [group-key command-key thread-pool-key run-fn fallback-fn cache-key-fn]} & args]
502-
(let [setter (doto (HystrixCommand$Setter/withGroupKey group-key)
503-
; TODO other properties
526+
[{:keys [group-key command-key thread-pool-key
527+
run-fn fallback-fn cache-key-fn
528+
init-fn] :as def-map} & args]
529+
(let [setter (-> (HystrixCommand$Setter/withGroupKey group-key)
504530
(.andCommandKey command-key)
505-
(.andThreadPoolKey thread-pool-key))]
506-
(proxy [HystrixCommand] [setter]
531+
(.andThreadPoolKey thread-pool-key))
532+
setter (if init-fn
533+
(init-fn def-map setter)
534+
setter)]
535+
(when (not (instance? HystrixCommand$Setter setter))
536+
(throw (IllegalStateException. (str ":init-fn didn't return HystrixCommand$Setter instance"))))
537+
(proxy [HystrixCommand] [^HystrixCommand$Setter setter]
507538
(run [] (apply run-fn args))
508539
(getFallback [] (if fallback-fn
509540
(apply fallback-fn args)
@@ -522,6 +553,7 @@
522553
((required-fn :map-fn))
523554
((optional-fn :shard-fn))
524555
((optional-fn :cache-key-fn))
556+
((optional-fn :init-fn))
525557

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

533565
(defmethod instantiate* :collapser
534-
[{:keys [collapser-key scope collapse-fn map-fn shard-fn cache-key-fn]} & args]
535-
(let [setter (doto (HystrixCollapser$Setter/withCollapserKey collapser-key)
536-
; TODO other properties
537-
(.andScope scope))]
538-
(proxy [HystrixCollapser] [setter]
566+
[{:keys [collapser-key scope
567+
collapse-fn map-fn shard-fn cache-key-fn
568+
init-fn] :as def-map} & args]
569+
(let [setter (-> (HystrixCollapser$Setter/withCollapserKey collapser-key)
570+
(.andScope scope))
571+
setter (if init-fn
572+
(init-fn def-map setter)
573+
setter)]
574+
(when (not (instance? HystrixCollapser$Setter setter))
575+
(throw (IllegalStateException. (str ":init-fn didn't return HystrixCollapser$Setter instance"))))
576+
(proxy [HystrixCollapser] [^HystrixCollapser$Setter setter]
539577
(getCacheKey [] (if cache-key-fn
540578
(apply cache-key-fn args)))
541579

hystrix-contrib/hystrix-clj/src/test/clojure/com/netflix/hystrix/core_test.clj

+29-12
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,15 @@
1616

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

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

33-
(use-fixtures :once clojuresque-shutdown-hack)
27+
(use-fixtures :once hystrix-reset-fixture)
3428

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

62+
(deftest test-normalize-command
63+
(testing "throws if :init-fn isn't a fn"
64+
(is (thrown-with-msg? IllegalArgumentException #"^.*init-fn.*$"
65+
(normalize {:type :command
66+
:run-fn +
67+
:init-fn 999})))))
68+
69+
(deftest test-normalize-collapser
70+
(testing "throws if :init-fn isn't a fn"
71+
(is (thrown-with-msg? IllegalArgumentException #"^.*init-fn.*$"
72+
(normalize {:type :collapser
73+
:collapse-fn (fn [& args])
74+
:map-fn (fn [& args])
75+
:init-fn "foo"})))))
76+
6877
(deftest test-instantiate
6978
(let [base-def {:type :command
7079
:group-key :my-group
@@ -74,6 +83,15 @@
7483
(let [c (instantiate (normalize base-def))]
7584
(is (instance? com.netflix.hystrix.HystrixCommand c))))
7685

86+
(testing "makes a HystrixCommand and calls :init-fn"
87+
(let [called (atom nil)
88+
init-fn (fn [d s] (reset! called [d s]) s)
89+
c (instantiate (normalize (assoc base-def :init-fn init-fn)))
90+
[d s] @called]
91+
(is (not (nil? @called)))
92+
(is (map? d))
93+
(is (instance? com.netflix.hystrix.HystrixCommand$Setter s))))
94+
7795
(testing "makes a HystrixCommand that executes :run-fn with given args"
7896
(let [c (instantiate (normalize base-def) 99 42)]
7997
(is (= 141 (.execute c)))))
@@ -159,8 +177,7 @@
159177
(is (.isDone qc))))))
160178

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

0 commit comments

Comments
 (0)