package com.hubspot.baragon.service.managers;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.hubspot.baragon.BaragonDataModule;
import com.hubspot.baragon.data.BaragonRequestDatastore;
import com.hubspot.baragon.models.BaragonServiceStatus;
import com.hubspot.baragon.service.BaragonServiceModule;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.Response;
import org.apache.curator.framework.recipes.leader.LeaderLatch;
import org.apache.curator.framework.state.ConnectionState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class StatusManager {
private static final Logger LOG = LoggerFactory.getLogger(StatusManager.class);
private final BaragonRequestDatastore requestDatastore;
private final LeaderLatch leaderLatch;
private final AtomicLong workerLastStart;
private final AtomicLong elbWorkerLastStart;
private final AtomicReference<ConnectionState> connectionState;
private final AsyncHttpClient httpClient;
private final ObjectMapper objectMapper;
@Inject
public StatusManager(BaragonRequestDatastore requestDatastore,
ObjectMapper objectMapper,
@Named(BaragonDataModule.BARAGON_SERVICE_LEADER_LATCH) LeaderLatch leaderLatch,
@Named(BaragonDataModule.BARAGON_SERVICE_WORKER_LAST_START) AtomicLong workerLastStart,
@Named(BaragonDataModule.BARAGON_ELB_WORKER_LAST_START) AtomicLong elbWorkerLastStart,
@Named(BaragonDataModule.BARAGON_ZK_CONNECTION_STATE) AtomicReference<ConnectionState> connectionState,
@Named(BaragonServiceModule.BARAGON_SERVICE_HTTP_CLIENT)AsyncHttpClient httpClient) {
this.requestDatastore = requestDatastore;
this.leaderLatch = leaderLatch;
this.workerLastStart = workerLastStart;
this.elbWorkerLastStart = elbWorkerLastStart;
this.connectionState = connectionState;
this.httpClient = httpClient;
this.objectMapper = objectMapper;
}
public BaragonServiceStatus getServiceStatus() {
final ConnectionState currentConnectionState = connectionState.get();
final String connectionStateString = currentConnectionState == null ? "UNKNOWN" : currentConnectionState.name();
final long workerLagMs = System.currentTimeMillis() - workerLastStart.get();
final long elbWorkerLagMs = System.currentTimeMillis() - elbWorkerLastStart.get();
if (connectionStateString.equals("CONNECTED") || connectionStateString.equals("RECONNECTED")) {
return new BaragonServiceStatus(leaderLatch.hasLeadership(), requestDatastore.getQueuedRequestCount(), workerLagMs, elbWorkerLagMs,connectionStateString);
} else {
return new BaragonServiceStatus(leaderLatch.hasLeadership(), 0, workerLagMs, elbWorkerLagMs, connectionStateString);
}
}
public BaragonServiceStatus getMasterServiceStatus() {
if (leaderLatch.hasLeadership()) {
return getServiceStatus();
} else {
try {
String leaderUri = leaderLatch.getLeader().getId();
Response response = httpClient.prepareGet(String.format("%s/status", leaderUri)).execute().get();
return objectMapper.readValue(response.getResponseBody(), BaragonServiceStatus.class);
} catch (Exception e) {
LOG.error("Error fetching status from leader", e);
return getServiceStatus();
}
}
}
}