All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.hyperfoil.api.connection.Request Maven / Gradle / Ivy

There is a newer version: 0.27
Show newest version
package io.hyperfoil.api.connection;

import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import io.hyperfoil.api.session.SequenceInstance;
import io.hyperfoil.api.session.Session;
import io.hyperfoil.api.session.SessionStopException;
import io.hyperfoil.api.statistics.Statistics;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.ScheduledFuture;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;

public abstract class Request implements Callable, GenericFutureListener> {
   private static final Logger log = LoggerFactory.getLogger(Request.class);
   private static final TimeoutException TIMEOUT_EXCEPTION = new TimeoutException();
   private static final GenericFutureListener> FAILURE_LISTENER = future -> {
      if (!future.isSuccess() && !future.isCancelled()) {
         log.error("Timeout task failed", future.cause());
      }
   };

   public final Session session;
   private long startTimestampMillis;
   private long startTimestampNanos;
   private long sendTimestampNanos;
   private SequenceInstance sequence;
   private Statistics statistics;
   private ScheduledFuture timeoutFuture;
   private Connection connection;
   private Status status = Status.IDLE;
   private Result result = Result.VALID;

   public Request(Session session) {
      this.session = session;
   }

   /**
    * This method works as timeout handler
    */
   @Override
   public Void call() {
      int uniqueId = session == null ? -1 : session.uniqueId();
      log.warn("#{} Request timeout on connection {}", uniqueId, connection);
      timeoutFuture = null;
      if (status != Status.COMPLETED) {
         result = Result.TIMED_OUT;
         statistics.incrementTimeouts(startTimestampMillis);
         try {
            handleThrowable(TIMEOUT_EXCEPTION);
         } catch (SessionStopException e) {
            // ignored
         }
         if (connection == null) {
            log.warn("#{} connection is already null", uniqueId);
         } else {
            connection.onTimeout(this);
         }
         // handleThrowable sets the request completed
      } else {
         log.trace("#{} Request {} is already completed.", uniqueId, this);
      }
      return null;
   }

   protected abstract void handleThrowable(Throwable throwable);

   public void start(SequenceInstance sequence, Statistics statistics) {
      this.startTimestampMillis = System.currentTimeMillis();
      this.startTimestampNanos = System.nanoTime();
      this.sequence = sequence;
      this.statistics = statistics;
      this.status = Status.RUNNING;
      this.result = Result.VALID;
   }

   public void attach(Connection connection) {
      this.connection = connection;
   }

   public Status status() {
      return status;
   }

   public boolean isValid() {
      return result == Result.VALID;
   }

   public void markInvalid() {
      result = Result.INVALID;
   }

   public void setCompleting() {
      status = Status.COMPLETING;
   }

   public boolean isRunning() {
      return status == Status.RUNNING;
   }

   public boolean isCompleted() {
      return status == Status.COMPLETED || status == Status.IDLE;
   }

   public void setCompleted() {
      if (timeoutFuture != null) {
         timeoutFuture.cancel(false);
         timeoutFuture = null;
      }
      connection = null;
      // handleEnd may indirectly call handleThrowable which calls setCompleted first
      if (status != Status.IDLE) {
         status = Status.COMPLETED;
      }
   }

   public Connection connection() {
      return connection;
   }

   public SequenceInstance sequence() {
      return sequence;
   }

   public Statistics statistics() {
      return statistics;
   }

   public long startTimestampMillis() {
      return startTimestampMillis;
   }

   public long startTimestampNanos() {
      return startTimestampNanos;
   }

   public long sendTimestampNanos() {
      return sendTimestampNanos;
   }

   public void setTimeout(long timeout, TimeUnit timeUnit) {
      timeoutFuture = session.executor().schedule(this, timeout, timeUnit);
      timeoutFuture.addListener(FAILURE_LISTENER);
   }

   @Override
   public void operationComplete(Future future) {
      // This is called when the request is written on the wire
      sendTimestampNanos = System.nanoTime();
   }

   public abstract void release();

   public void enter() {
      session.currentSequence(sequence);
      session.currentRequest(this);
   }

   public void exit() {
      session.currentSequence(null);
      session.currentRequest(null);
   }

   protected void setIdle() {
      status = Status.IDLE;
   }

   public enum Result {
      VALID,
      INVALID,
      TIMED_OUT,
   }

   public enum Status {
      IDLE, // in pool
      RUNNING,
      COMPLETING,
      COMPLETED,
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy