30
30
import java .util .Set ;
31
31
import java .util .concurrent .ConcurrentHashMap ;
32
32
import java .util .concurrent .Executor ;
33
- import java .util .concurrent .atomic .AtomicBoolean ;
34
33
import java .util .concurrent .atomic .AtomicLong ;
35
34
import java .util .stream .Collectors ;
36
35
import org .slf4j .Logger ;
37
36
import org .slf4j .LoggerFactory ;
38
37
39
38
public class DiscoveryServer {
40
39
41
- private static final Logger LOGGER = LoggerFactory .getLogger (DiscoveryServer .class );
42
-
43
40
static final String ANY_TYPE_URL = "" ;
44
-
41
+ private static final Logger LOGGER = LoggerFactory . getLogger ( DiscoveryServer . class );
45
42
private final List <DiscoveryServerCallbacks > callbacks ;
46
43
private final ConfigWatcher configWatcher ;
47
44
private final ExecutorGroup executorGroup ;
@@ -58,7 +55,8 @@ public DiscoveryServer(DiscoveryServerCallbacks callbacks, ConfigWatcher configW
58
55
59
56
/**
60
57
* Creates the server.
61
- * @param callbacks server callbacks
58
+ *
59
+ * @param callbacks server callbacks
62
60
* @param configWatcher source of configuration updates
63
61
*/
64
62
public DiscoveryServer (List <DiscoveryServerCallbacks > callbacks , ConfigWatcher configWatcher ) {
@@ -67,9 +65,10 @@ public DiscoveryServer(List<DiscoveryServerCallbacks> callbacks, ConfigWatcher c
67
65
68
66
/**
69
67
* Creates the server.
70
- * @param callbacks server callbacks
71
- * @param configWatcher source of configuration updates
72
- * @param executorGroup executor group to use for responding stream requests
68
+ *
69
+ * @param callbacks server callbacks
70
+ * @param configWatcher source of configuration updates
71
+ * @param executorGroup executor group to use for responding stream requests
73
72
* @param protoResourcesSerializer serializer of proto buffer messages
74
73
*/
75
74
public DiscoveryServer (List <DiscoveryServerCallbacks > callbacks ,
@@ -162,7 +161,8 @@ public StreamObserver<DiscoveryRequest> streamRoutes(
162
161
*/
163
162
public SecretDiscoveryServiceGrpc .SecretDiscoveryServiceImplBase getSecretDiscoveryServiceImpl () {
164
163
return new SecretDiscoveryServiceGrpc .SecretDiscoveryServiceImplBase () {
165
- @ Override public StreamObserver <DiscoveryRequest > streamSecrets (
164
+ @ Override
165
+ public StreamObserver <DiscoveryRequest > streamSecrets (
166
166
StreamObserver <DiscoveryResponse > responseObserver ) {
167
167
return createRequestHandler (responseObserver , false , Resources .SECRET_TYPE_URL );
168
168
}
@@ -201,7 +201,7 @@ private class DiscoveryRequestStreamObserver implements StreamObserver<Discovery
201
201
private final long streamId ;
202
202
private final boolean ads ;
203
203
private final Executor executor ;
204
- private final AtomicBoolean isClosing = new AtomicBoolean () ;
204
+ private boolean isClosing ;
205
205
206
206
private AtomicLong streamNonce ;
207
207
@@ -214,10 +214,10 @@ public DiscoveryRequestStreamObserver(String defaultTypeUrl,
214
214
this .responseObserver = responseObserver ;
215
215
this .streamId = streamId ;
216
216
this .ads = ads ;
217
- watches = new ConcurrentHashMap <>(Resources .TYPE_URLS .size ());
218
- latestResponse = new ConcurrentHashMap <>(Resources .TYPE_URLS .size ());
219
- ackedResources = new ConcurrentHashMap <>(Resources .TYPE_URLS .size ());
220
- streamNonce = new AtomicLong ();
217
+ this . watches = new ConcurrentHashMap <>(Resources .TYPE_URLS .size ());
218
+ this . latestResponse = new ConcurrentHashMap <>(Resources .TYPE_URLS .size ());
219
+ this . ackedResources = new ConcurrentHashMap <>(Resources .TYPE_URLS .size ());
220
+ this . streamNonce = new AtomicLong ();
221
221
this .executor = executor ;
222
222
}
223
223
@@ -228,10 +228,15 @@ public void onNext(DiscoveryRequest request) {
228
228
229
229
if (defaultTypeUrl .equals (ANY_TYPE_URL )) {
230
230
if (requestTypeUrl .isEmpty ()) {
231
- responseObserver .onError (
232
- Status .UNKNOWN
233
- .withDescription (String .format ("[%d] type URL is required for ADS" , streamId ))
234
- .asRuntimeException ());
231
+ synchronized (responseObserver ) {
232
+ if (!isClosing ) {
233
+ isClosing = true ;
234
+ responseObserver .onError (
235
+ Status .UNKNOWN
236
+ .withDescription (String .format ("[%d] type URL is required for ADS" , streamId ))
237
+ .asRuntimeException ());
238
+ }
239
+ }
235
240
236
241
return ;
237
242
}
@@ -292,7 +297,12 @@ public void onError(Throwable t) {
292
297
293
298
try {
294
299
callbacks .forEach (cb -> cb .onStreamCloseWithError (streamId , defaultTypeUrl , t ));
295
- responseObserver .onError (Status .fromThrowable (t ).asException ());
300
+ synchronized (responseObserver ) {
301
+ if (!isClosing ) {
302
+ isClosing = true ;
303
+ responseObserver .onError (Status .fromThrowable (t ).asException ());
304
+ }
305
+ }
296
306
} finally {
297
307
cancel ();
298
308
}
@@ -304,7 +314,12 @@ public void onCompleted() {
304
314
305
315
try {
306
316
callbacks .forEach (cb -> cb .onStreamClose (streamId , defaultTypeUrl ));
307
- responseObserver .onCompleted ();
317
+ synchronized (responseObserver ) {
318
+ if (!isClosing ) {
319
+ isClosing = true ;
320
+ responseObserver .onCompleted ();
321
+ }
322
+ }
308
323
} finally {
309
324
cancel ();
310
325
}
@@ -316,8 +331,11 @@ void onCancelled() {
316
331
}
317
332
318
333
private void closeWithError (Throwable exception ) {
319
- if (isClosing .compareAndSet (false , true )) {
320
- responseObserver .onError (exception );
334
+ synchronized (responseObserver ) {
335
+ if (!isClosing ) {
336
+ isClosing = true ;
337
+ responseObserver .onError (exception );
338
+ }
321
339
}
322
340
cancel ();
323
341
}
@@ -345,11 +363,15 @@ private void send(Response response, String typeUrl) {
345
363
// is processed the map is guaranteed to be updated. Doing it afterwards leads to a race conditions
346
364
// which may see the incoming request arrive before the map is updated, failing the nonce check erroneously.
347
365
latestResponse .put (typeUrl , discoveryResponse );
348
- try {
349
- responseObserver .onNext (discoveryResponse );
350
- } catch (StatusRuntimeException e ) {
351
- if (!Status .CANCELLED .getCode ().equals (e .getStatus ().getCode ())) {
352
- throw e ;
366
+ synchronized (responseObserver ) {
367
+ if (!isClosing ) {
368
+ try {
369
+ responseObserver .onNext (discoveryResponse );
370
+ } catch (StatusRuntimeException e ) {
371
+ if (!Status .CANCELLED .getCode ().equals (e .getStatus ().getCode ())) {
372
+ throw e ;
373
+ }
374
+ }
353
375
}
354
376
}
355
377
}
0 commit comments