예제 #1
0
  /** Sets up the given connection. */
  private CompletableFuture<Connection> setupConnection(Connection connection) {
    this.connection = connection;
    connection.closeListener(
        c -> {
          if (c.equals(this.connection)) {
            this.connection = null;
          }
        });
    connection.exceptionListener(
        c -> {
          if (c.equals(this.connection)) {
            this.connection = null;
          }
        });
    connection.handler(PublishRequest.class, this::handlePublish);

    if (id != 0) {
      ConnectRequest request = ConnectRequest.builder().withSession(id).build();

      CompletableFuture<Connection> future = new CompletableFuture<>();
      connection
          .send(request)
          .whenComplete(
              (response, error) -> {
                if (isOpen()) {
                  if (error == null) {
                    future.complete(connection);
                  } else {
                    future.completeExceptionally(error);
                  }
                }
              });
      return future;
    }
    return CompletableFuture.completedFuture(connection);
  }
예제 #2
0
  /**
   * Sends a session request to the given connection.
   *
   * @param request The request to send.
   * @param connection The connection to which to send the request.
   * @param future The future to complete once the response is received.
   * @param checkOpen Whether to check if the session is open.
   * @param <T> The request type.
   * @param <U> The response type.
   * @return The provided future to be completed once the response is received.
   */
  private <T extends Request<T>, U extends Response<U>> CompletableFuture<U> request(
      T request,
      Connection connection,
      CompletableFuture<U> future,
      boolean checkOpen,
      boolean recordFailures) {
    LOGGER.debug("Sending: {}", request);
    connection
        .<T, U>send(request)
        .whenComplete(
            (response, error) -> {
              if (!checkOpen || isOpen()) {
                if (error == null) {
                  LOGGER.debug("Received: {}", response);

                  // If the response is an error response, check if the session state has changed.
                  if (response.status() == Response.Status.ERROR) {
                    // If the response error is a no leader error, reset the connection and send
                    // another request.
                    // If this is the first time we've received a response from a server in this
                    // iteration,
                    // set the failure time to keep track of whether the session timed out.
                    if (response.error() == RaftError.Type.NO_LEADER_ERROR) {
                      if (recordFailures) setFailureTime();
                      resetConnection().request(request, future, checkOpen, false);
                    }
                    // If the response error is an unknown session error, immediately expire the
                    // session.
                    else if (response.error() == RaftError.Type.UNKNOWN_SESSION_ERROR) {
                      resetConnection().onExpire();
                      future.completeExceptionally(new IllegalStateException("session expired"));
                    }
                    // If the response error is an application or internal error, immediately
                    // complete the future.
                    else if (response.error() == RaftError.Type.APPLICATION_ERROR
                        || response.error() == RaftError.Type.INTERNAL_ERROR) {
                      resetFailureTime();
                      future.completeExceptionally(response.error().createException());
                    }
                    // If we've made it this far, for all other error types attempt to resend the
                    // request.
                    else {
                      resetFailureTime()
                          .resetConnection()
                          .request(request, future, checkOpen, false);
                    }
                  }
                  // If the response status is OK, reset the failure time and complete the future.
                  else {
                    resetFailureTime();
                    future.complete(response);
                  }
                }
                // If an error occurred, attempt to contact the next server recursively.
                else {
                  LOGGER.debug("Request failed: {}", request);
                  LOGGER.debug("{}", error.getMessage());
                  resetConnection().request(request, future, checkOpen, recordFailures);
                }
              } else {
                future.completeExceptionally(new IllegalStateException("session not open"));
              }
            });
    return future;
  }