Handle WebSocket sendMessage errors with onErrorResume
This commit is contained in:
		
							parent
							
								
									b701412295
								
							
						
					
					
						commit
						2d187abf13
					
				| 
						 | 
					@ -352,6 +352,8 @@ public class WebSocketConnection implements MessageAvailabilityListener, Displac
 | 
				
			||||||
    final Publisher<Envelope> messages =
 | 
					    final Publisher<Envelope> messages =
 | 
				
			||||||
        messagesManager.getMessagesForDeviceReactive(auth.getAccount().getUuid(), device.getId(), cachedMessagesOnly);
 | 
					        messagesManager.getMessagesForDeviceReactive(auth.getAccount().getUuid(), device.getId(), cachedMessagesOnly);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final AtomicBoolean hasErrored = new AtomicBoolean();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final Disposable subscription = Flux.from(messages)
 | 
					    final Disposable subscription = Flux.from(messages)
 | 
				
			||||||
        .name(SEND_MESSAGES_FLUX_NAME)
 | 
					        .name(SEND_MESSAGES_FLUX_NAME)
 | 
				
			||||||
        .tap(Micrometer.metrics(Metrics.globalRegistry))
 | 
					        .tap(Micrometer.metrics(Metrics.globalRegistry))
 | 
				
			||||||
| 
						 | 
					@ -359,28 +361,23 @@ public class WebSocketConnection implements MessageAvailabilityListener, Displac
 | 
				
			||||||
        .flatMapSequential(envelope ->
 | 
					        .flatMapSequential(envelope ->
 | 
				
			||||||
            Mono.fromFuture(() -> sendMessage(envelope)
 | 
					            Mono.fromFuture(() -> sendMessage(envelope)
 | 
				
			||||||
                .orTimeout(sendFuturesTimeoutMillis, TimeUnit.MILLISECONDS)))
 | 
					                .orTimeout(sendFuturesTimeoutMillis, TimeUnit.MILLISECONDS)))
 | 
				
			||||||
 | 
					        .onErrorResume(
 | 
				
			||||||
 | 
					            // let the first error pass through to terminate the subscription
 | 
				
			||||||
 | 
					            e -> {
 | 
				
			||||||
 | 
					              final boolean firstError = !hasErrored.getAndSet(true);
 | 
				
			||||||
 | 
					              measureSendMessageErrors(e, firstError);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              return !firstError;
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            // otherwise just emit nothing
 | 
				
			||||||
 | 
					            e -> Mono.empty()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        .subscribeOn(messageDeliveryScheduler)
 | 
					        .subscribeOn(messageDeliveryScheduler)
 | 
				
			||||||
        .subscribe(
 | 
					        .subscribe(
 | 
				
			||||||
            // no additional consumer of values - it is Flux<Void> by now
 | 
					            // no additional consumer of values - it is Flux<Void> by now
 | 
				
			||||||
            null,
 | 
					            null,
 | 
				
			||||||
            // the first error will terminate the stream, but we may get multiple errors from in-flight messages
 | 
					            // this first error will terminate the stream, but we may get multiple errors from in-flight messages
 | 
				
			||||||
            e -> {
 | 
					            queueCleared::completeExceptionally,
 | 
				
			||||||
              queueCleared.completeExceptionally(e);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
              final String errorType;
 | 
					 | 
				
			||||||
              if (e instanceof TimeoutException) {
 | 
					 | 
				
			||||||
                errorType = "timeout";
 | 
					 | 
				
			||||||
              } else if (e instanceof java.nio.channels.ClosedChannelException) {
 | 
					 | 
				
			||||||
                errorType = "closedChannel";
 | 
					 | 
				
			||||||
              } else {
 | 
					 | 
				
			||||||
                logger.warn("Send message failed", e);
 | 
					 | 
				
			||||||
                errorType = "other";
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
              final Tags tags = Tags.of(
 | 
					 | 
				
			||||||
                  UserAgentTagUtil.getPlatformTag(client.getUserAgent()),
 | 
					 | 
				
			||||||
                  Tag.of(ERROR_TYPE_TAG, errorType));
 | 
					 | 
				
			||||||
              Metrics.counter(SEND_MESSAGE_ERROR_COUNTER, tags).increment();
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            // completion
 | 
					            // completion
 | 
				
			||||||
            () -> queueCleared.complete(null)
 | 
					            () -> queueCleared.complete(null)
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
| 
						 | 
					@ -388,6 +385,22 @@ public class WebSocketConnection implements MessageAvailabilityListener, Displac
 | 
				
			||||||
    messageSubscription.set(subscription);
 | 
					    messageSubscription.set(subscription);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private void measureSendMessageErrors(Throwable e, final boolean terminal) {
 | 
				
			||||||
 | 
					    final String errorType;
 | 
				
			||||||
 | 
					    if (e instanceof TimeoutException) {
 | 
				
			||||||
 | 
					      errorType = "timeout";
 | 
				
			||||||
 | 
					    } else if (e instanceof java.nio.channels.ClosedChannelException) {
 | 
				
			||||||
 | 
					      errorType = "closedChannel";
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      logger.warn(terminal ? "Send message failure terminated stream" : "Send message failed", e);
 | 
				
			||||||
 | 
					      errorType = "other";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    final Tags tags = Tags.of(
 | 
				
			||||||
 | 
					        UserAgentTagUtil.getPlatformTag(client.getUserAgent()),
 | 
				
			||||||
 | 
					        Tag.of(ERROR_TYPE_TAG, errorType));
 | 
				
			||||||
 | 
					    Metrics.counter(SEND_MESSAGE_ERROR_COUNTER, tags).increment();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private CompletableFuture<Void> sendMessage(Envelope envelope) {
 | 
					  private CompletableFuture<Void> sendMessage(Envelope envelope) {
 | 
				
			||||||
    final UUID messageGuid = UUID.fromString(envelope.getServerGuid());
 | 
					    final UUID messageGuid = UUID.fromString(envelope.getServerGuid());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue