Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.mesosphere.mesos.http-adapter.MesosToSchedulerDriverAdapter Maven / Gradle / Ivy
package com.mesosphere.mesos.HTTPAdapter;
import com.google.api.client.util.ExponentialBackOff;
import com.google.common.annotations.VisibleForTesting;
import com.google.protobuf.ByteString;
import com.mesosphere.mesos.protobuf.EvolverDevolver;
import org.apache.mesos.v1.scheduler.Mesos;
import org.apache.mesos.v1.scheduler.Protos;
import org.apache.mesos.v1.scheduler.V0Mesos;
import org.apache.mesos.v1.scheduler.V1Mesos;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.OptionalLong;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* This is a threadsafe adapter from the new v1 `Mesos` + `Scheduler` interface to the old v0 `SchedulerDriver`
* + `Scheduler` interface. It intercepts:
* - The v1 scheduler callbacks and converts them into appropriate v0 scheduler callbacks.
* - The various `driver.xx()` calls, creates a `Call` message and then invokes `send()` on the v1
* `Mesos` interface.
*/
public class MesosToSchedulerDriverAdapter implements
org.apache.mesos.v1.scheduler.Scheduler,
org.apache.mesos.SchedulerDriver {
private static final Logger LOGGER = LoggerFactory.getLogger(MesosToSchedulerDriverAdapter.class);
// State of the `Mesos` interface.
private enum State {
DISCONNECTED,
CONNECTED,
SUBSCRIBED
}
// Exponential back-off between consecutive subscribe calls.
private static final int MULTIPLIER = 2;
private static final int SEED_BACKOFF_MS = 2000;
private static final int MAX_BACKOFF_MS = 30000;
// Latch for supporting `join()`.
private CountDownLatch latch = new CountDownLatch(1);
private org.apache.mesos.Scheduler wrappedScheduler;
private org.apache.mesos.v1.Protos.FrameworkInfo frameworkInfo;
private final String master;
private final org.apache.mesos.v1.Protos.Credential credential;
// TODO(anand): This can change to `v1.Status` once we add support for devolving enums.
private org.apache.mesos.Protos.Status status;
private boolean registered;
private final boolean implicitAcknowledgements;
private Mesos mesos;
private volatile ScheduledExecutorService subscriberTimer;
private State state;
private ScheduledExecutorService heartbeatTimer;
private Instant lastHeartbeat;
private OptionalLong heartbeatTimeout;
public MesosToSchedulerDriverAdapter(org.apache.mesos.Scheduler wrappedScheduler,
org.apache.mesos.Protos.FrameworkInfo frameworkInfo,
String master,
boolean implicitAcknowledgements) {
this.wrappedScheduler = wrappedScheduler;
this.frameworkInfo = EvolverDevolver.evolve(frameworkInfo);
this.credential = null;
this.master = master;
this.registered = false;
this.implicitAcknowledgements = implicitAcknowledgements;
this.status = org.apache.mesos.Protos.Status.DRIVER_NOT_STARTED;
this.state = State.DISCONNECTED;
}
public MesosToSchedulerDriverAdapter(org.apache.mesos.Scheduler wrappedScheduler,
org.apache.mesos.Protos.FrameworkInfo frameworkInfo,
String master,
boolean implicitAcknowledgements,
org.apache.mesos.Protos.Credential credential) {
this.wrappedScheduler = wrappedScheduler;
this.frameworkInfo = EvolverDevolver.evolve(frameworkInfo);
this.master = master;
this.credential = EvolverDevolver.evolve(credential);
this.registered = false;
this.implicitAcknowledgements = implicitAcknowledgements;
this.status = org.apache.mesos.Protos.Status.DRIVER_NOT_STARTED;
this.state = State.DISCONNECTED;
}
@Override
public synchronized void connected(Mesos mesos) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return;
}
LOGGER.info("Connected!");
state = State.CONNECTED;
performReliableSubscription();
}
private synchronized void subscribe(ExponentialBackOff backOff) throws IOException {
if (state == State.SUBSCRIBED || state == State.DISCONNECTED) {
cancelSubscriber();
return;
}
LOGGER.info("Sending SUBSCRIBE call");
final Protos.Call.Builder callBuilder = Protos.Call.newBuilder()
.setType(Protos.Call.Type.SUBSCRIBE)
.setSubscribe(Protos.Call.Subscribe.newBuilder()
.setFrameworkInfo(frameworkInfo)
.build());
if (frameworkInfo.hasId()) {
callBuilder.setFrameworkId(frameworkInfo.getId());
}
mesos.send(callBuilder.build());
scheduleNextSubscription(backOff);
}
private synchronized void scheduleNextSubscription(ExponentialBackOff backOff) throws IOException {
long nextBackoffMs;
nextBackoffMs = backOff.nextBackOffMillis();
LOGGER.info("Backing off for: {}", nextBackoffMs);
subscriberTimer.schedule(new SubscriberTask(backOff), nextBackoffMs, TimeUnit.MILLISECONDS);
}
/**
* Task that performs Subscription.
*/
private synchronized void performReliableSubscription() {
// If timer is not running, initialize it.
if (subscriberTimer == null) {
LOGGER.info("Initializing reliable subscriber");
subscriberTimer = createTimerInternal();
ExponentialBackOff backOff = new ExponentialBackOff.Builder()
.setMaxElapsedTimeMillis(Integer.MAX_VALUE /* Try forever */)
.setMaxIntervalMillis(MAX_BACKOFF_MS)
.setMultiplier(MULTIPLIER)
.setRandomizationFactor(0.5)
.setInitialIntervalMillis(SEED_BACKOFF_MS)
.build();
subscriberTimer.schedule(new SubscriberTask(backOff), SEED_BACKOFF_MS, TimeUnit.MILLISECONDS);
}
}
@Override
public synchronized void disconnected(Mesos mesos) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return;
}
LOGGER.info("Disconnected!");
state = State.DISCONNECTED;
cancelSubscriber();
cancelHeartbeatTimer();
wrappedScheduler.disconnected(this);
}
@Override
public synchronized void received(Mesos mesos, Protos.Event v1Event) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return;
}
org.apache.mesos.scheduler.Protos.Event event = EvolverDevolver.devolve(v1Event);
LOGGER.info("Received event of type: {}", event.getType());
switch (event.getType()) {
case SUBSCRIBED: {
state = State.SUBSCRIBED;
frameworkInfo = org.apache.mesos.v1.Protos.FrameworkInfo.newBuilder(frameworkInfo)
.setId(v1Event.getSubscribed().getFrameworkId())
.build();
if (!registered) {
registered = true;
wrappedScheduler.registered(
this,
EvolverDevolver.devolve(frameworkInfo.getId()),
EvolverDevolver.devolve(v1Event.getSubscribed().getMasterInfo()));
} else {
wrappedScheduler.reregistered(
this,
EvolverDevolver.devolve(v1Event.getSubscribed().getMasterInfo()));
}
initHeartbeatTimer(event.getSubscribed().getHeartbeatIntervalSeconds());
LOGGER.info("Subscribed with ID " + frameworkInfo.getId());
break;
}
case OFFERS: {
wrappedScheduler.resourceOffers(this, event.getOffers().getOffersList());
break;
}
case INVERSE_OFFERS:
break;
case RESCIND: {
wrappedScheduler.offerRescinded(this, event.getRescind().getOfferId());
break;
}
case RESCIND_INVERSE_OFFER:
break;
case UPDATE: {
final org.apache.mesos.v1.Protos.TaskStatus v1Status = v1Event.getUpdate().getStatus();
wrappedScheduler.statusUpdate(this, event.getUpdate().getStatus());
// The underlying implementations do not automatically
// send acknowledgements. IFF we have
// 'implicitAcknowledgements' turned on, AND a UUID is
// set then we send an ACK.
if (implicitAcknowledgements && v1Status.hasUuid()) {
final org.apache.mesos.v1.Protos.AgentID agentId = v1Status.getAgentId();
final org.apache.mesos.v1.Protos.TaskID taskId = v1Status.getTaskId();
mesos.send(Protos.Call.newBuilder()
.setType(Protos.Call.Type.ACKNOWLEDGE)
.setFrameworkId(frameworkInfo.getId())
.setAcknowledge(Protos.Call.Acknowledge.newBuilder()
.setAgentId(agentId)
.setTaskId(taskId)
.setUuid(v1Status.getUuid())
.build())
.build());
}
break;
}
case MESSAGE: {
wrappedScheduler.frameworkMessage(
this,
event.getMessage().getExecutorId(),
event.getMessage().getSlaveId(),
event.getMessage().getData().toByteArray());
break;
}
case FAILURE: {
final org.apache.mesos.scheduler.Protos.Event.Failure failure = event.getFailure();
if (failure.hasSlaveId() && failure.hasExecutorId()) {
wrappedScheduler.executorLost(
this,
failure.getExecutorId(),
failure.getSlaveId(),
failure.getStatus());
} else {
wrappedScheduler.slaveLost(this, failure.getSlaveId());
}
break;
}
case ERROR: {
wrappedScheduler.error(this, event.getError().getMessage());
break;
}
case HEARTBEAT: {
lastHeartbeat = Instant.now();
break;
}
case UNKNOWN: {
LOGGER.error("Received an unsupported event: {}", event);
break;
}
default: {
LOGGER.error("Received an unsupported event: {}", event);
break;
}
}
}
@Override
public synchronized org.apache.mesos.Protos.Status start() {
if (status != org.apache.mesos.Protos.Status.DRIVER_NOT_STARTED) {
return status;
}
this.mesos = startInternal();
return status = org.apache.mesos.Protos.Status.DRIVER_RUNNING;
}
/**
* Broken out into a separate function to allow testing with custom `Mesos` implementations.
*/
@VisibleForTesting
protected Mesos startInternal() {
String version = System.getenv("MESOS_API_VERSION");
if (version == null) {
version = "V0";
}
LOGGER.info("Using Mesos API version: {}", version);
if (version.equals("V0")) {
if (credential == null) {
return new V0Mesos(this, frameworkInfo, master);
} else {
return new V0Mesos(this, frameworkInfo, master, credential);
}
} else if (version.equals("V1")) {
if (credential == null) {
return new V1Mesos(this, master);
} else {
return new V1Mesos(this, master, credential);
}
} else {
throw new IllegalArgumentException("Unsupported API version: " + version);
}
}
private void initHeartbeatTimer(double heartbeatInterval) {
heartbeatTimeout = OptionalLong.of(5 * (long) heartbeatInterval);
lastHeartbeat = Instant.now();
heartbeatTimer = createTimerInternal();
heartbeatTimer.scheduleWithFixedDelay(
() -> heartbeat(mesos),
heartbeatTimeout.getAsLong(),
heartbeatTimeout.getAsLong(),
TimeUnit.MILLISECONDS);
}
/**
* Broken out into a separate function to allow speeding up the `Timer` callbacks.
*/
@VisibleForTesting
protected ScheduledExecutorService createTimerInternal() {
return Executors.newSingleThreadScheduledExecutor();
}
private synchronized void cancelHeartbeatTimer() {
if (heartbeatTimer == null) {
return;
}
LOGGER.info("Cancelling heartbeat timer upon disconnection");
heartbeatTimer.shutdownNow();
heartbeatTimer = null;
heartbeatTimeout = null;
lastHeartbeat = null;
}
@Override
public synchronized org.apache.mesos.Protos.Status stop(boolean failover) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
if (!failover) {
mesos.send(org.apache.mesos.v1.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.v1.scheduler.Protos.Call.Type.TEARDOWN)
.setFrameworkId(frameworkInfo.getId())
.build());
}
// This should ensure that the underlying native implementation is eventually GC'ed.
this.mesos = null;
this.latch.countDown();
return status = org.apache.mesos.Protos.Status.DRIVER_STOPPED;
}
@Override
public synchronized org.apache.mesos.Protos.Status stop() {
return stop(false);
}
@Override
public synchronized org.apache.mesos.Protos.Status abort() {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
// This should ensure that the underlying native implementation is eventually GC'ed.
this.mesos = null;
this.latch.countDown();
return status = org.apache.mesos.Protos.Status.DRIVER_ABORTED;
}
@Override
public org.apache.mesos.Protos.Status join() {
// Wait for `stop()` or `abort()` to trigger the latch.
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (this) {
return status;
}
}
@Override
public org.apache.mesos.Protos.Status run() {
org.apache.mesos.Protos.Status status = start();
return status != org.apache.mesos.Protos.Status.DRIVER_RUNNING ? status : join();
}
@Override
public synchronized org.apache.mesos.Protos.Status requestResources(
Collection requests) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.REQUEST)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.setRequest(org.apache.mesos.scheduler.Protos.Call.Request.newBuilder()
.addAllRequests(requests)
.build())
.build()));
return org.apache.mesos.Protos.Status.DRIVER_RUNNING;
}
@Override
public synchronized org.apache.mesos.Protos.Status launchTasks(Collection offerIds,
Collection tasks,
org.apache.mesos.Protos.Filters filters) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.ACCEPT)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.setAccept(org.apache.mesos.scheduler.Protos.Call.Accept.newBuilder()
.addAllOfferIds(offerIds)
.addOperations(org.apache.mesos.Protos.Offer.Operation.newBuilder()
.setType(org.apache.mesos.Protos.Offer.Operation.Type.LAUNCH)
.setLaunch(org.apache.mesos.Protos.Offer.Operation.Launch.newBuilder()
.addAllTaskInfos(tasks)))
.build())
.build()));
return status;
}
@Override
public synchronized org.apache.mesos.Protos.Status launchTasks(Collection offerIds,
Collection tasks) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.ACCEPT)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.setAccept(org.apache.mesos.scheduler.Protos.Call.Accept.newBuilder()
.addAllOfferIds(offerIds)
.addOperations(org.apache.mesos.Protos.Offer.Operation.newBuilder()
.setType(org.apache.mesos.Protos.Offer.Operation.Type.LAUNCH)
.setLaunch(org.apache.mesos.Protos.Offer.Operation.Launch.newBuilder()
.addAllTaskInfos(tasks)))
.build())
.build()));
return status;
}
@Override
public synchronized org.apache.mesos.Protos.Status launchTasks(org.apache.mesos.Protos.OfferID offerId,
Collection tasks,
org.apache.mesos.Protos.Filters filters) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.ACCEPT)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.setAccept(org.apache.mesos.scheduler.Protos.Call.Accept.newBuilder()
.addOfferIds(offerId)
.addOperations(org.apache.mesos.Protos.Offer.Operation.newBuilder()
.setType(org.apache.mesos.Protos.Offer.Operation.Type.LAUNCH)
.setLaunch(org.apache.mesos.Protos.Offer.Operation.Launch.newBuilder()
.addAllTaskInfos(tasks))
.build())
.setFilters(filters))
.build()));
return status;
}
@Override
public synchronized org.apache.mesos.Protos.Status launchTasks(org.apache.mesos.Protos.OfferID offerId,
Collection tasks) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.ACCEPT)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.setAccept(org.apache.mesos.scheduler.Protos.Call.Accept.newBuilder()
.addOfferIds(offerId)
.addOperations(org.apache.mesos.Protos.Offer.Operation.newBuilder()
.setType(org.apache.mesos.Protos.Offer.Operation.Type.LAUNCH)
.setLaunch(org.apache.mesos.Protos.Offer.Operation.Launch.newBuilder()
.addAllTaskInfos(tasks)))
.build())
.build()));
return status;
}
@Override
public synchronized org.apache.mesos.Protos.Status killTask(org.apache.mesos.Protos.TaskID taskId) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.KILL)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.setKill(org.apache.mesos.scheduler.Protos.Call.Kill.newBuilder()
.setTaskId(taskId)
.build())
.build()));
return status;
}
@Override
public synchronized org.apache.mesos.Protos.Status acceptOffers(
Collection offerIds,
Collection operations,
org.apache.mesos.Protos.Filters filters) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.ACCEPT)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.setAccept(org.apache.mesos.scheduler.Protos.Call.Accept.newBuilder()
.addAllOfferIds(offerIds)
.addAllOperations(operations)
.setFilters(filters)
.build())
.build()));
return status;
}
@Override
public synchronized org.apache.mesos.Protos.Status declineOffer(org.apache.mesos.Protos.OfferID offerId,
org.apache.mesos.Protos.Filters filters) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.DECLINE)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.setDecline(org.apache.mesos.scheduler.Protos.Call.Decline.newBuilder()
.addOfferIds(offerId)
.setFilters(filters)
.build())
.build()));
return status;
}
@Override
public synchronized org.apache.mesos.Protos.Status declineOffer(org.apache.mesos.Protos.OfferID offerId) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.DECLINE)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.setDecline(org.apache.mesos.scheduler.Protos.Call.Decline.newBuilder()
.addOfferIds(offerId)
.build())
.build()));
return status;
}
@Override
public synchronized org.apache.mesos.Protos.Status reviveOffers() {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.REVIVE)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.build()));
return status;
}
@Override
public synchronized org.apache.mesos.Protos.Status suppressOffers() {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.SUPPRESS)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.build()));
return status;
}
@Override
public synchronized org.apache.mesos.Protos.Status acknowledgeStatusUpdate(
org.apache.mesos.Protos.TaskStatus statusToAck) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.ACKNOWLEDGE)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.setAcknowledge(org.apache.mesos.scheduler.Protos.Call.Acknowledge.newBuilder()
.setSlaveId(statusToAck.getSlaveId())
.setTaskId(statusToAck.getTaskId())
.setUuid(statusToAck.getUuid())
.build())
.build()));
return status;
}
@Override
public synchronized org.apache.mesos.Protos.Status sendFrameworkMessage(
org.apache.mesos.Protos.ExecutorID executorId,
org.apache.mesos.Protos.SlaveID slaveId,
byte[] data) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.MESSAGE)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.setMessage(org.apache.mesos.scheduler.Protos.Call.Message.newBuilder()
.setData(ByteString.copyFrom(data))
.setExecutorId(executorId)
.setSlaveId(slaveId)
.build())
.build()));
return status;
}
@Override
public synchronized org.apache.mesos.Protos.Status reconcileTasks(
Collection statuses) {
if (status != org.apache.mesos.Protos.Status.DRIVER_RUNNING) {
return status;
}
List tasks = new ArrayList<>();
for (org.apache.mesos.Protos.TaskStatus status : statuses) {
org.apache.mesos.scheduler.Protos.Call.Reconcile.Task.Builder builder =
org.apache.mesos.scheduler.Protos.Call.Reconcile.Task.newBuilder();
builder.setTaskId(status.getTaskId());
if (status.hasSlaveId()) {
builder.setSlaveId(status.getSlaveId());
}
tasks.add(builder.build());
}
mesos.send(EvolverDevolver.evolve(org.apache.mesos.scheduler.Protos.Call.newBuilder()
.setType(org.apache.mesos.scheduler.Protos.Call.Type.RECONCILE)
.setFrameworkId(EvolverDevolver.devolve(frameworkInfo.getId()))
.setReconcile(org.apache.mesos.scheduler.Protos.Call.Reconcile.newBuilder()
.addAllTasks(tasks)
.build())
.build()));
return status;
}
@VisibleForTesting
protected synchronized Instant getLastHeartbeat() {
return lastHeartbeat;
}
private synchronized void cancelSubscriber() {
if (subscriberTimer == null) {
return;
}
LOGGER.info("Cancelling subscriber");
subscriberTimer.shutdownNow();
subscriberTimer = null;
}
private synchronized void heartbeat(final Mesos mesos) {
// Don't bother checking for heartbeats if we are not subscribed.
if (state == State.DISCONNECTED || state == State.CONNECTED) {
return;
}
Duration elapsed = Duration.between(lastHeartbeat, Instant.now());
// Force reconnection if we have not received heartbeats.
if (elapsed.getSeconds() >= heartbeatTimeout.getAsLong()) {
LOGGER.info("Forcing reconnection with the master due to not receiving heartbeat events for "
+ elapsed.getSeconds() + " seconds");
mesos.reconnect();
// Cancel the heartbeat timer now to prevent further reconnects. It is possible that we got partitioned
// away from the master and are not able to reconnect. If we don't cancel the timer, we would trigger
// reconnection again.
cancelHeartbeatTimer();
}
}
/**
* Sends subscription call, and rescehdules next subscription attempt.
*/
public class SubscriberTask implements Runnable {
ExponentialBackOff backOff;
public SubscriberTask(ExponentialBackOff backOff) {
this.backOff = backOff;
}
@Override
public void run() {
try {
subscribe(backOff);
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
}
}
}