|
13 | 13 | [com.netflix.hystrix.exception HystrixBadRequestException] |
14 | 14 | [org.slf4j MDC])) |
15 | 15 |
|
16 | | -(def ^:private ^:const hystrix-keys |
17 | | - #{:hystrix/fallback-fn |
18 | | - :hystrix/group-key |
19 | | - :hystrix/command-key |
20 | | - :hystrix/threads |
21 | | - :hystrix/queue-size |
22 | | - :hystrix/timeout-ms |
23 | | - :hystrix/breaker-request-volume |
24 | | - :hystrix/breaker-error-percent |
25 | | - :hystrix/breaker-sleep-window-ms |
26 | | - :hystrix/bad-request-pred}) |
27 | | - |
28 | 16 | (defn default-fallback [req resp] |
29 | 17 | (if (:status resp) |
30 | 18 | resp |
31 | 19 | {:status 503})) |
32 | 20 |
|
| 21 | +(defn client-error? |
| 22 | + "Returns true when the response has one of the 4xx family of status |
| 23 | + codes" |
| 24 | + [req resp] |
| 25 | + (http/client-error? resp)) |
| 26 | + |
33 | 27 | (defn ^:private handle-exception |
34 | 28 | [f req] |
35 | 29 | (let [^Exception raw-response (try (f) (catch Exception e e)) |
|
40 | 34 | ((http/wrap-exceptions (constantly resp)) req)) |
41 | 35 | resp)) |
42 | 36 |
|
| 37 | +(def ^:private ^:const hystrix-defaults |
| 38 | + {:hystrix/command-key :default |
| 39 | + :hystrix/fallback-fn default-fallback |
| 40 | + :hystrix/group-key :default |
| 41 | + :hystrix/threads 10 |
| 42 | + :hystrix/queue-size 5 |
| 43 | + :hystrix/timeout-ms 1000 |
| 44 | + :hystrix/breaker-request-volume 20 |
| 45 | + :hystrix/breaker-error-percent 50 |
| 46 | + :hystrix/breaker-sleep-window-ms 5000 |
| 47 | + :hystrix/bad-request-pred client-error?}) |
| 48 | + |
| 49 | +(def ^:private hystrix-keys |
| 50 | + (keys hystrix-defaults)) |
| 51 | + |
43 | 52 | (defn ^:private group-key [s] |
44 | 53 | (HystrixCommandGroupKey$Factory/asKey (name s))) |
45 | 54 |
|
|
49 | 58 | (defn ^:private configurator |
50 | 59 | "Create a configurator that can configure the hystrix according to the |
51 | 60 | declarative config (or some sensible defaults)" |
52 | | - [config] |
53 | | - (let [timeout (:hystrix/timeout-ms config 1000) |
54 | | - group (:hystrix/group-key config :default) |
55 | | - threads (:hystrix/threads config 10) |
56 | | - request-volume (:hystrix/breaker-request-volume config 20) |
57 | | - error-percent (:hystrix/breaker-error-percent config 50) |
58 | | - sleep-window (:hystrix/breaker-sleep-window-ms config 5000) |
| 61 | + ^HystrixCommand$Setter [config] |
| 62 | + (let [{group :hystrix/group-key |
| 63 | + command :hystrix/command-key |
| 64 | + timeout :hystrix/timeout-ms |
| 65 | + threads :hystrix/threads |
| 66 | + queue-size :hystrix/queue-size |
| 67 | + sleep-window :hystrix/breaker-sleep-window-ms |
| 68 | + error-percent :hystrix/breaker-error-percent |
| 69 | + request-volume :hystrix/breaker-request-volume} config |
59 | 70 | command-configurator (doto (HystrixCommandProperties/Setter) |
60 | 71 | (.withExecutionIsolationThreadTimeoutInMilliseconds timeout) |
61 | 72 | (.withCircuitBreakerRequestVolumeThreshold request-volume) |
|
64 | 75 | (.withMetricsRollingPercentileEnabled false)) |
65 | 76 | thread-pool-configurator (doto (HystrixThreadPoolProperties/Setter) |
66 | 77 | (.withCoreSize threads) |
67 | | - (.withMaxQueueSize (:hystrix/queue-size config 5)) |
68 | | - (.withQueueSizeRejectionThreshold (:hystrix/queue-size config 5)))] |
| 78 | + (.withMaxQueueSize queue-size) |
| 79 | + (.withQueueSizeRejectionThreshold queue-size))] |
69 | 80 | (doto (HystrixCommand$Setter/withGroupKey (group-key group)) |
70 | | - (.andCommandKey (command-key (:hystrix/command-key config :default))) |
| 81 | + (.andCommandKey (command-key command)) |
71 | 82 | (.andCommandPropertiesDefaults command-configurator) |
72 | 83 | (.andThreadPoolPropertiesDefaults thread-pool-configurator)))) |
73 | 84 |
|
|
85 | 96 | (fn [req resp] |
86 | 97 | (contains? status-codes (:status resp))))) |
87 | 98 |
|
88 | | -(defn client-error? |
89 | | - "Returns true when the response has one of the 4xx family of status |
90 | | - codes" |
91 | | - [req resp] |
92 | | - (http/client-error? resp)) |
93 | | - |
94 | 99 | (defn wrap-hystrix |
95 | 100 | "Wrap a clj-http client request with hystrix features (but only if a |
96 | 101 | command-key is present in the options map)." |
97 | 102 | [f req] |
98 | 103 | (if (not-empty (select-keys req hystrix-keys)) |
99 | | - (let [bad-request-pred (:hystrix/bad-request-pred req client-error?) |
100 | | - fallback (:hystrix/fallback-fn req default-fallback) |
| 104 | + (let [req (merge hystrix-defaults req) |
| 105 | + bad-request-pred (:hystrix/bad-request-pred req) |
| 106 | + fallback (:hystrix/fallback-fn req) |
101 | 107 | wrap-bad-request (fn [resp] (if (bad-request-pred req resp) |
102 | 108 | (throw (HystrixBadRequestException. "Ignored bad request" |
103 | 109 | (wrap {:object resp |
104 | 110 | :message "Bad request pred" |
105 | 111 | :stack-trace (stack-trace)}))) |
106 | 112 | resp)) |
107 | 113 | wrap-exception-response (fn [resp] ((http/wrap-exceptions (constantly resp)) (assoc req :throw-exceptions true))) |
108 | | - ^HystrixCommand$Setter configurator (configurator req) |
| 114 | + configurator (configurator req) |
109 | 115 | logging-context (or (MDC/getCopyOfContextMap) {}) |
110 | 116 | command (proxy [HystrixCommand] [configurator] |
111 | 117 | (getFallback [] |
|
0 commit comments