|
20 | 20 | import com.netflix.hystrix.HystrixThreadPoolKey; |
21 | 21 | import com.netflix.hystrix.HystrixThreadPoolMetrics; |
22 | 22 | import rx.Observable; |
23 | | -import rx.functions.Func0; |
| 23 | +import rx.functions.Action0; |
24 | 24 | import rx.functions.Func1; |
25 | 25 |
|
26 | 26 | import java.util.HashMap; |
27 | 27 | import java.util.Map; |
28 | 28 | import java.util.concurrent.TimeUnit; |
| 29 | +import java.util.concurrent.atomic.AtomicBoolean; |
29 | 30 |
|
30 | 31 | /** |
31 | 32 | * This class samples current Hystrix utilization of resources and exposes that as a stream |
32 | 33 | */ |
33 | 34 | public class HystrixUtilizationStream { |
34 | | - |
35 | 35 | private final int intervalInMilliseconds; |
36 | | - private final Observable<Long> timer; |
| 36 | + private final Observable<HystrixUtilization> allUtilizationStream; |
| 37 | + private final AtomicBoolean isSourceCurrentlySubscribed = new AtomicBoolean(false); |
37 | 38 |
|
| 39 | + /** |
| 40 | + * @deprecated Not for public use. Please use {@link #getInstance()}. This facilitates better stream-sharing |
| 41 | + * @param intervalInMilliseconds milliseconds between data emissions |
| 42 | + */ |
| 43 | + @Deprecated //deprecated in 1.5.4. |
38 | 44 | public HystrixUtilizationStream(final int intervalInMilliseconds) { |
39 | 45 | this.intervalInMilliseconds = intervalInMilliseconds; |
40 | | - this.timer = Observable.defer(new Func0<Observable<Long>>() { |
41 | | - @Override |
42 | | - public Observable<Long> call() { |
43 | | - return Observable.interval(intervalInMilliseconds, TimeUnit.MILLISECONDS); |
44 | | - } |
45 | | - }); |
| 46 | + this.allUtilizationStream = Observable.interval(intervalInMilliseconds, TimeUnit.MILLISECONDS) |
| 47 | + .map(getAllUtilization) |
| 48 | + .doOnSubscribe(new Action0() { |
| 49 | + @Override |
| 50 | + public void call() { |
| 51 | + isSourceCurrentlySubscribed.set(true); |
| 52 | + } |
| 53 | + }) |
| 54 | + .doOnUnsubscribe(new Action0() { |
| 55 | + @Override |
| 56 | + public void call() { |
| 57 | + isSourceCurrentlySubscribed.set(false); |
| 58 | + } |
| 59 | + }) |
| 60 | + .share() |
| 61 | + .onBackpressureDrop(); |
46 | 62 | } |
47 | 63 |
|
| 64 | + private static final HystrixUtilizationStream INSTANCE = new HystrixUtilizationStream(500); |
| 65 | + |
| 66 | + public static HystrixUtilizationStream getInstance() { |
| 67 | + return INSTANCE; |
| 68 | + } |
| 69 | + |
| 70 | + static HystrixUtilizationStream getNonSingletonInstanceOnlyUsedInUnitTests(int delayInMs) { |
| 71 | + return new HystrixUtilizationStream(delayInMs); |
| 72 | + } |
| 73 | + |
| 74 | + /** |
| 75 | + * Return a ref-counted stream that will only do work when at least one subscriber is present |
| 76 | + */ |
48 | 77 | public Observable<HystrixUtilization> observe() { |
49 | | - return timer.map(getAllUtilization); |
| 78 | + return allUtilizationStream; |
50 | 79 | } |
51 | 80 |
|
52 | 81 | public Observable<Map<HystrixCommandKey, HystrixCommandUtilization>> observeCommandUtilization() { |
53 | | - return timer.map(getAllCommandUtilization); |
| 82 | + return allUtilizationStream.map(getOnlyCommandUtilization); |
54 | 83 | } |
55 | 84 |
|
56 | 85 | public Observable<Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization>> observeThreadPoolUtilization() { |
57 | | - return timer.map(getAllThreadPoolUtilization); |
| 86 | + return allUtilizationStream.map(getOnlyThreadPoolUtilization); |
58 | 87 | } |
59 | 88 |
|
60 | 89 | public int getIntervalInMilliseconds() { |
61 | 90 | return this.intervalInMilliseconds; |
62 | 91 | } |
63 | 92 |
|
| 93 | + public boolean isSourceCurrentlySubscribed() { |
| 94 | + return isSourceCurrentlySubscribed.get(); |
| 95 | + } |
| 96 | + |
64 | 97 | private static HystrixCommandUtilization sampleCommandUtilization(HystrixCommandMetrics commandMetrics) { |
65 | 98 | return HystrixCommandUtilization.sample(commandMetrics); |
66 | 99 | } |
@@ -105,4 +138,20 @@ public HystrixUtilization call(Long timestamp) { |
105 | 138 | ); |
106 | 139 | } |
107 | 140 | }; |
| 141 | + |
| 142 | + private static final Func1<HystrixUtilization, Map<HystrixCommandKey, HystrixCommandUtilization>> getOnlyCommandUtilization = |
| 143 | + new Func1<HystrixUtilization, Map<HystrixCommandKey, HystrixCommandUtilization>>() { |
| 144 | + @Override |
| 145 | + public Map<HystrixCommandKey, HystrixCommandUtilization> call(HystrixUtilization hystrixUtilization) { |
| 146 | + return hystrixUtilization.getCommandUtilizationMap(); |
| 147 | + } |
| 148 | + }; |
| 149 | + |
| 150 | + private static final Func1<HystrixUtilization, Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization>> getOnlyThreadPoolUtilization = |
| 151 | + new Func1<HystrixUtilization, Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization>>() { |
| 152 | + @Override |
| 153 | + public Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization> call(HystrixUtilization hystrixUtilization) { |
| 154 | + return hystrixUtilization.getThreadPoolUtilizationMap(); |
| 155 | + } |
| 156 | + }; |
108 | 157 | } |
0 commit comments