1
1
/*
2
- * Copyright 2018-2020 the original author or authors.
2
+ * Copyright 2018-2021 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
21
21
import reactor .util .function .Tuple2 ;
22
22
23
23
import java .net .InetSocketAddress ;
24
+ import java .time .Duration ;
24
25
import java .util .ArrayList ;
25
26
import java .util .Collection ;
26
27
import java .util .Collections ;
30
31
import java .util .concurrent .ConcurrentHashMap ;
31
32
import java .util .function .Supplier ;
32
33
34
+ import org .slf4j .Logger ;
35
+ import org .slf4j .LoggerFactory ;
33
36
import org .springframework .data .elasticsearch .client .ElasticsearchHost ;
34
37
import org .springframework .data .elasticsearch .client .ElasticsearchHost .State ;
35
38
import org .springframework .data .elasticsearch .client .NoReachableHostException ;
42
45
*
43
46
* @author Christoph Strobl
44
47
* @author Mark Paluch
48
+ * @author Peter-Josef Meisch
45
49
* @since 3.2
46
50
*/
47
- class MultiNodeHostProvider implements HostProvider {
51
+ class MultiNodeHostProvider implements HostProvider <MultiNodeHostProvider > {
52
+
53
+ private final static Logger LOG = LoggerFactory .getLogger (MultiNodeHostProvider .class );
48
54
49
55
private final WebClientProvider clientProvider ;
50
56
private final Supplier <HttpHeaders > headersSupplier ;
51
57
private final Map <InetSocketAddress , ElasticsearchHost > hosts ;
52
58
53
- MultiNodeHostProvider (WebClientProvider clientProvider , Supplier <HttpHeaders > headersSupplier , InetSocketAddress ... endpoints ) {
59
+ MultiNodeHostProvider (WebClientProvider clientProvider , Supplier <HttpHeaders > headersSupplier ,
60
+ InetSocketAddress ... endpoints ) {
54
61
55
62
this .clientProvider = clientProvider ;
56
63
this .headersSupplier = headersSupplier ;
57
64
this .hosts = new ConcurrentHashMap <>();
58
65
for (InetSocketAddress endpoint : endpoints ) {
59
66
this .hosts .put (endpoint , new ElasticsearchHost (endpoint , State .UNKNOWN ));
60
67
}
68
+
69
+ LOG .debug ("initialized with " + hosts );
61
70
}
62
71
63
72
/*
@@ -66,7 +75,7 @@ class MultiNodeHostProvider implements HostProvider {
66
75
*/
67
76
@ Override
68
77
public Mono <ClusterInformation > clusterInfo () {
69
- return nodes (null ).map (this ::updateNodeState ).buffer (hosts .size ())
78
+ return checkNodes (null ).map (this ::updateNodeState ).buffer (hosts .size ())
70
79
.then (Mono .just (new ClusterInformation (new LinkedHashSet <>(this .hosts .values ()))));
71
80
}
72
81
@@ -86,14 +95,19 @@ public WebClient createWebClient(InetSocketAddress endpoint) {
86
95
@ Override
87
96
public Mono <InetSocketAddress > lookupActiveHost (Verification verification ) {
88
97
98
+ LOG .trace ("lookupActiveHost " + verification + " from " + hosts ());
99
+
89
100
if (Verification .LAZY .equals (verification )) {
90
101
for (ElasticsearchHost entry : hosts ()) {
91
102
if (entry .isOnline ()) {
103
+ LOG .trace ("lookupActiveHost returning " + entry );
92
104
return Mono .just (entry .getEndpoint ());
93
105
}
94
106
}
107
+ LOG .trace ("no online host found with LAZY" );
95
108
}
96
109
110
+ LOG .trace ("searching for active host" );
97
111
return findActiveHostInKnownActives () //
98
112
.switchIfEmpty (findActiveHostInUnresolved ()) //
99
113
.switchIfEmpty (findActiveHostInDead ()) //
@@ -105,20 +119,30 @@ Collection<ElasticsearchHost> getCachedHostState() {
105
119
}
106
120
107
121
private Mono <InetSocketAddress > findActiveHostInKnownActives () {
108
- return findActiveForSate (State .ONLINE );
122
+ return findActiveForState (State .ONLINE );
109
123
}
110
124
111
125
private Mono <InetSocketAddress > findActiveHostInUnresolved () {
112
- return findActiveForSate (State .UNKNOWN );
126
+ return findActiveForState (State .UNKNOWN );
113
127
}
114
128
115
129
private Mono <InetSocketAddress > findActiveHostInDead () {
116
- return findActiveForSate (State .OFFLINE );
130
+ return findActiveForState (State .OFFLINE );
117
131
}
118
132
119
- private Mono <InetSocketAddress > findActiveForSate (State state ) {
120
- return nodes (state ).map (this ::updateNodeState ).filter (ElasticsearchHost ::isOnline )
121
- .map (ElasticsearchHost ::getEndpoint ).next ();
133
+ private Mono <InetSocketAddress > findActiveForState (State state ) {
134
+
135
+ LOG .trace ("findActiveForState state " + state + ", current hosts: " + hosts );
136
+
137
+ return checkNodes (state ) //
138
+ .map (this ::updateNodeState ) //
139
+ .filter (ElasticsearchHost ::isOnline ) //
140
+ .map (elasticsearchHost -> {
141
+ LOG .trace ("findActiveForState returning host " + elasticsearchHost );
142
+ return elasticsearchHost ;
143
+ }).map (ElasticsearchHost ::getEndpoint ) //
144
+ .takeLast (1 ) //
145
+ .next ();
122
146
}
123
147
124
148
private ElasticsearchHost updateNodeState (Tuple2 <InetSocketAddress , ClientResponse > tuple2 ) {
@@ -129,17 +153,19 @@ private ElasticsearchHost updateNodeState(Tuple2<InetSocketAddress, ClientRespon
129
153
return elasticsearchHost ;
130
154
}
131
155
132
- private Flux <Tuple2 <InetSocketAddress , ClientResponse >> nodes (@ Nullable State state ) {
156
+ private Flux <Tuple2 <InetSocketAddress , ClientResponse >> checkNodes (@ Nullable State state ) {
133
157
134
158
return Flux .fromIterable (hosts ()) //
135
159
.filter (entry -> state == null || entry .getState ().equals (state )) //
136
160
.map (ElasticsearchHost ::getEndpoint ) //
137
- .flatMap (host -> {
161
+ .concatMap (host -> {
138
162
139
163
Mono <ClientResponse > exchange = createWebClient (host ) //
140
164
.head ().uri ("/" ) //
141
165
.headers (httpHeaders -> httpHeaders .addAll (headersSupplier .get ())) //
142
- .exchange ().doOnError (throwable -> {
166
+ .exchange () //
167
+ .timeout (Duration .ofSeconds (1 )) //
168
+ .doOnError (throwable -> {
143
169
hosts .put (host , new ElasticsearchHost (host , State .OFFLINE ));
144
170
clientProvider .getErrorListener ().accept (throwable );
145
171
});
0 commit comments