io.camunda.zeebe.transport.impl.RequestContext Maven / Gradle / Ivy
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
* one or more contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright ownership.
* Licensed under the Camunda License 1.0. You may not use this file
* except in compliance with the Camunda License 1.0.
*/
package io.camunda.zeebe.transport.impl;
import static io.camunda.zeebe.transport.impl.AtomixServerTransport.topicName;
import io.atomix.utils.net.Address;
import io.camunda.zeebe.scheduler.ScheduledTimer;
import io.camunda.zeebe.scheduler.clock.ActorClock;
import io.camunda.zeebe.scheduler.future.CompletableActorFuture;
import io.camunda.zeebe.transport.RequestType;
import java.time.Duration;
import java.util.concurrent.TimeoutException;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.agrona.DirectBuffer;
final class RequestContext {
private final CompletableActorFuture currentFuture;
private final Supplier nodeAddressSupplier;
private final int partitionId;
private final RequestType requestType;
private final byte[] requestBytes;
private final boolean shouldRetry;
private final long startTime;
private final Duration timeout;
private final Predicate responseValidator;
private ScheduledTimer scheduledTimer;
RequestContext(
final CompletableActorFuture currentFuture,
final Supplier nodeAddressSupplier,
final int partitionId,
final RequestType requestType,
final byte[] requestBytes,
final Predicate responseValidator,
final boolean shouldRetry,
final Duration timeout) {
this.currentFuture = currentFuture;
this.nodeAddressSupplier = nodeAddressSupplier;
this.partitionId = partitionId;
this.requestType = requestType;
this.requestBytes = requestBytes;
this.shouldRetry = shouldRetry;
startTime = ActorClock.currentTimeMillis();
this.responseValidator = responseValidator;
this.timeout = timeout;
}
public boolean isDone() {
return currentFuture.isDone();
}
Address getNodeAddress() {
final var address = nodeAddressSupplier.get();
return address == null ? null : Address.from(address);
}
String getTopicName() {
return topicName(partitionId, requestType);
}
byte[] getRequestBytes() {
return requestBytes;
}
public Duration getTimeout() {
return timeout;
}
/**
* @return the time out, which is calculated via given timeout minus the already elapsed time.
* this is necessary to respect the retries
*/
Duration calculateTimeout() {
final var currentTime = ActorClock.currentTimeMillis();
final var elapsedTime = currentTime - startTime;
return timeout.minus(Duration.ofMillis(elapsedTime));
}
boolean verifyResponse(final DirectBuffer response) {
// the predicate returns true when the response is valid and the request should not be retried
return responseValidator.test(response);
}
public void complete(final DirectBuffer buffer) {
currentFuture.complete(buffer);
cancelTimer();
}
public void completeExceptionally(final Throwable throwable) {
currentFuture.completeExceptionally(throwable);
cancelTimer();
}
private void cancelTimer() {
if (scheduledTimer != null) {
scheduledTimer.cancel();
}
}
public void setScheduledTimer(final ScheduledTimer scheduledTimer) {
this.scheduledTimer = scheduledTimer;
}
public void timeout() {
currentFuture.completeExceptionally(
new TimeoutException("Request timed out after " + timeout.toString()));
}
public boolean shouldRetry() {
return shouldRetry;
}
}