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

com.hubspot.singularity.data.history.SingularityRequestHistoryPersister Maven / Gradle / Ivy

The newest version!
package com.hubspot.singularity.data.history;

import com.google.common.primitives.Longs;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import com.hubspot.mesos.JavaUtils;
import com.hubspot.singularity.SingularityDeleteResult;
import com.hubspot.singularity.SingularityHistoryItem;
import com.hubspot.singularity.SingularityManagedThreadPoolFactory;
import com.hubspot.singularity.SingularityRequestHistory;
import com.hubspot.singularity.async.CompletableFutures;
import com.hubspot.singularity.config.SingularityConfiguration;
import com.hubspot.singularity.data.RequestManager;
import com.hubspot.singularity.data.history.SingularityRequestHistoryPersister.SingularityRequestHistoryParent;
import com.hubspot.singularity.mesos.SingularitySchedulerLock;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import javax.inject.Singleton;
import javax.ws.rs.HEAD;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Singleton
public class SingularityRequestHistoryPersister
  extends SingularityHistoryPersister {
  private static final Logger LOG = LoggerFactory.getLogger(
    SingularityRequestHistoryPersister.class
  );

  private final RequestManager requestManager;
  private final HistoryManager historyManager;
  private final SingularitySchedulerLock lock;

  @Inject
  public SingularityRequestHistoryPersister(
    SingularityConfiguration configuration,
    RequestManager requestManager,
    HistoryManager historyManager,
    SingularitySchedulerLock lock,
    SingularityManagedThreadPoolFactory managedThreadPoolFactory,
    @Named(SingularityHistoryModule.PERSISTER_LOCK) ReentrantLock persisterLock,
    @Named(
      SingularityHistoryModule.LAST_REQUEST_PERSISTER_SUCCESS
    ) AtomicLong lastPersisterSuccess
  ) {
    super(configuration, persisterLock, lastPersisterSuccess, managedThreadPoolFactory);
    this.requestManager = requestManager;
    this.historyManager = historyManager;
    this.lock = lock;
  }

  public static class SingularityRequestHistoryParent
    implements SingularityHistoryItem, Comparable {
    private final List history;
    private final String requestId;
    private final long createTime;

    public SingularityRequestHistoryParent(
      List history,
      String requestId
    ) {
      this.history = history;
      this.requestId = requestId;

      long newestTimestamp = 0;

      for (SingularityRequestHistory historyItem : history) {
        if (historyItem.getCreatedAt() > newestTimestamp) {
          newestTimestamp = historyItem.getCreatedAt();
        }
      }

      createTime = newestTimestamp;
    }

    public String getRequestId() {
      return requestId;
    }

    @Override
    public long getCreateTimestampForCalculatingHistoryAge() {
      return createTime;
    }

    @Override
    public int compareTo(SingularityRequestHistoryParent o) {
      return Longs.compare(
        this.getCreateTimestampForCalculatingHistoryAge(),
        o.getCreateTimestampForCalculatingHistoryAge()
      );
    }

    @Override
    public boolean equals(Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }
      SingularityRequestHistoryParent that = (SingularityRequestHistoryParent) o;
      return (
        createTime == that.createTime &&
        Objects.equals(history, that.history) &&
        Objects.equals(requestId, that.requestId)
      );
    }

    @Override
    public int hashCode() {
      return Objects.hash(history, requestId, createTime);
    }

    @Override
    public String toString() {
      return (
        "SingularityRequestHistoryParent[" +
        "history=" +
        history +
        ", requestId='" +
        requestId +
        '\'' +
        ", createTime=" +
        createTime +
        ']'
      );
    }
  }

  @Override
  public void runActionOnPoll() {
    LOG.info("Attempting to grab persister lock");
    persisterLock.lock();
    AtomicBoolean persisterSuccess = new AtomicBoolean(true);
    try {
      LOG.info("Checking request history for persistence");

      final long start = System.currentTimeMillis();

      final List requestHistoryParents = new ArrayList();

      AtomicInteger numHistoryTransferred = new AtomicInteger();

      for (String requestId : requestManager.getRequestIdsWithHistory()) {
        requestHistoryParents.add(
          new SingularityRequestHistoryParent(
            requestManager.getRequestHistory(requestId),
            requestId
          )
        );
      }

      Collections.sort(requestHistoryParents, Collections.reverseOrder()); // createdAt descending

      AtomicInteger i = new AtomicInteger();
      List> futures = new ArrayList<>();
      for (SingularityRequestHistoryParent requestHistoryParent : requestHistoryParents) {
        futures.add(
          CompletableFuture.runAsync(
            () ->
              lock.runWithRequestLock(
                () -> {
                  if (
                    moveToHistoryOrCheckForPurge(
                      requestHistoryParent,
                      i.getAndIncrement()
                    )
                  ) {
                    numHistoryTransferred.getAndAdd(requestHistoryParent.history.size());
                  } else {
                    LOG.error(
                      "Request History Persister failed on {}",
                      requestHistoryParent
                    );
                    persisterSuccess.getAndSet(false);
                  }
                },
                requestHistoryParent.requestId,
                "request history purger",
                SingularitySchedulerLock.Priority.LOW
              ),
            persisterExecutor
          )
        );
      }

      CompletableFutures.allOf(futures).join();
      LOG.info(
        "Transferred {} history updates for {} requests in {}",
        numHistoryTransferred,
        requestHistoryParents.size(),
        JavaUtils.duration(start)
      );
    } finally {
      if (persisterSuccess.get()) {
        lastPersisterSuccess.set(System.currentTimeMillis());
        LOG.info(
          "Finished run on request history persister at {}",
          lastPersisterSuccess.get()
        );
      }

      persisterLock.unlock();
    }
  }

  @Override
  protected long getMaxAgeInMillisOfItem() {
    return TimeUnit.HOURS.toMillis(
      configuration.getDeleteStaleRequestsFromZkWhenNoDatabaseAfterHours()
    );
  }

  @Override
  protected Optional getMaxNumberOfItems() {
    return configuration.getMaxRequestsWithHistoryInZkWhenNoDatabase();
  }

  @Override
  protected boolean moveToHistory(SingularityRequestHistoryParent object) {
    for (SingularityRequestHistory requestHistory : object.history) {
      try {
        historyManager.saveRequestHistoryUpdate(requestHistory);
      } catch (Throwable t) {
        LOG.error("Failed to persist {} into History", requestHistory, t);
        return false;
      }

      requestManager.deleteHistoryItem(requestHistory);
    }

    return true;
  }

  @Override
  protected SingularityDeleteResult purgeFromZk(SingularityRequestHistoryParent object) {
    return requestManager.deleteHistoryParent(object.requestId);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy