/**
   * This blocking function attempts to send the message passed in as a parameter. This {@link
   * AmqpsIotHubConnection} handles all calls to this method.
   *
   * <p>Only the first call to this method will result in an attempt to send. Until the message has
   * been sent, all other calls to this method will block. Once a message has been sent and this
   * method notified that it has been sent, this method will be invoked again if was previously
   * another call to send a message.
   *
   * <p>If a message has been passed down to the handler for sending but the message isn't sent
   * after a default constant number of seconds, the {@link AmqpsTransport} will set an ERROR status
   * code on the message and it will placed back onto the queue.
   *
   * @throws IOException If {@link AmqpsIotHubConnectionBaseHandler} has not been initialized.
   */
  protected synchronized void send(Tuple<CompletableFuture<Boolean>, byte[], Object> message)
      throws IOException {
    if (this.state == ReactorState.CLOSED) {
      throw new IllegalStateException(
          "The AMQPS IotHub Connection is currently closed. Call open() before attempting to send a message.");
    }
    if (message != null) {
      if (this.inProgressMessageMap.size() >= this.maxQueueSize * 0.9) {
        message.V1.completeExceptionally(
            new Throwable("Insufficient link credit to send message."));
      } else {
        try {
          // Use the content and ID fields of the input message to have the handler create and send
          // the message
          CompletableFuture<Integer> deliveryFuture =
              amqpsHandler.createBinaryMessage((byte[]) message.V2, message.V3);

          // Wait for a period of time before rejecting the message
          new Thread(
                  () -> {
                    try {
                      Thread.sleep(DEFAULT_DELIVERY_WAIT_TIME_SECONDS * 1000);
                      deliveryFuture.completeExceptionally(
                          new Throwable("Default timeout exceeded before this message was sent."));
                    } catch (InterruptedException e) {
                      e.printStackTrace();
                    }
                  })
              .start();

          // Wait for the deliveryFuture to be completed, providing the delivery hash code.
          // When this future completes, the message has been SENT
          Integer deliveryHash = deliveryFuture.get();
          inProgressMessageMap.put(deliveryHash, message);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        // The message was unable to be sent, exceptionally complete that future causing the message
        // to be put back on the queue.
        catch (ExecutionException e) {
          message.V1.completeExceptionally(e.getCause());
          this.fail(e.getCause());
        }
        // There was some other problem sending, exceptionally complete that future causing the
        // message to be put back on the queue.
        catch (Exception e) {
          if (message != null) {
            message.V1.completeExceptionally(e);
          }
          this.fail(e);
        }
      }
    } else {
      throw new IOException("Cannot send an unitialized message.");
    }
  }
Ejemplo n.º 2
0
  private <T> void retryHelper(
      BiFunction<Integer, Integer, CompletableFuture<T>> function, CompletableFuture<T> result) {
    final int retries = doRetry(function);
    final int index = getNextIndex(function);
    final long start = System.currentTimeMillis();
    if (index > -1) {
      try {
        function
            .apply(index, retries)
            .whenComplete(
                (obj, ex) -> {
                  if (ex == null) {
                    registerSuccess(function, index, start);
                    result.complete(obj);

                  } else {
                    if (retries > 0) {
                      registerFailure(function, index, false);
                      retryHelper(function, result);

                    } else {
                      registerFailure(function, index, true);
                      result.completeExceptionally(ex);
                    }
                  }
                });

      } catch (Exception e) {
        if (retries > 0) {
          registerFailure(function, index, false);
          retryHelper(function, result);

        } else {
          registerFailure(function, index, true);
          result.completeExceptionally(e);
        }
      }

    } else {
      result.completeExceptionally(new LoadBalancerException("All backends suspended"));
    }
  }