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

com.hubspot.blazar.util.SingularityBuildWatcher Maven / Gradle / Ivy

The newest version!
package com.hubspot.blazar.util;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.inject.Inject;
import javax.inject.Singleton;

import org.apache.curator.framework.recipes.leader.LeaderLatchListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.codahale.metrics.MetricRegistry;
import com.google.common.base.Optional;
import com.google.inject.name.Named;
import com.hubspot.blazar.base.ModuleBuild;
import com.hubspot.blazar.base.ModuleBuild.State;
import com.hubspot.blazar.config.BlazarConfiguration;
import com.hubspot.blazar.config.ExecutorConfiguration;
import com.hubspot.blazar.config.SingularityConfiguration;
import com.hubspot.blazar.data.service.ModuleBuildService;
import com.hubspot.blazar.listener.SingularityTaskKiller;
import com.hubspot.singularity.ExtendedTaskState;
import com.hubspot.singularity.SingularityTaskHistory;
import com.hubspot.singularity.SingularityTaskHistoryUpdate;
import com.hubspot.singularity.SingularityTaskIdHistory;
import com.hubspot.singularity.client.SingularityClient;
import io.dropwizard.lifecycle.Managed;

@Singleton
public class SingularityBuildWatcher implements LeaderLatchListener, Managed {
  private static final Logger LOG = LoggerFactory.getLogger(SingularityBuildWatcher.class);

  private final ScheduledExecutorService executorService;
  private final ModuleBuildService moduleBuildService;
  private final SingularityClient singularityClient;
  private final SingularityTaskKiller singularityTaskKiller;
  private final MetricRegistry metricRegistry;
  private final SingularityConfiguration singularityConfiguration;
  private final ExecutorConfiguration executorConfiguration;
  private final AtomicBoolean running;
  private final AtomicBoolean leader;

  @Inject
  public SingularityBuildWatcher(@Named("QueueProcessor") ScheduledExecutorService executorService,
                                 ModuleBuildService moduleBuildService,
                                 SingularityClient singularityClient,
                                 SingularityTaskKiller singularityTaskKiller,
                                 MetricRegistry metricRegistry,
                                 BlazarConfiguration blazarConfiguration) {
    this.executorService = executorService;
    this.moduleBuildService = moduleBuildService;
    this.singularityClient = singularityClient;
    this.singularityTaskKiller = singularityTaskKiller;
    this.metricRegistry = metricRegistry;
    this.singularityConfiguration = blazarConfiguration.getSingularityConfiguration();
    this.executorConfiguration = blazarConfiguration.getExecutorConfiguration();

    this.running = new AtomicBoolean();
    this.leader = new AtomicBoolean();
  }

  @Override
  public void start() throws Exception {
    running.set(true);
    executorService.scheduleAtFixedRate(new BuildChecker(), 0, 10, TimeUnit.SECONDS);
  }

  @Override
  public void stop() throws Exception {
    running.set(false);
  }

  @Override
  public void isLeader() {
    leader.set(true);
  }

  @Override
  public void notLeader() {
    leader.set(false);
  }

  private class BuildChecker implements Runnable {

    @Override
    public void run() {
      try {
        if (running.get() && leader.get()) {
          for (ModuleBuild build : moduleBuildService.getByState(State.LAUNCHING)) {
            long age = System.currentTimeMillis() - build.getStartTimestamp().get();
            if (age < TimeUnit.MINUTES.toMillis(1)) {
              continue;
            }

            String requestId = singularityConfiguration.getRequest();
            String runId =  String.valueOf(build.getId().get());
            Optional task = singularityClient.getHistoryForTask(requestId, runId);
            if (task.isPresent()) {
              Optional taskState = task.get().getLastTaskState();
              if (taskState.isPresent() && taskState.get().isDone()) {
                String taskId = task.get().getTaskId().getId();
                LOG.info("Updating build {} to FAILED because taskId {} is done", build.getId().get(), taskId);
                moduleBuildService.update(build.withState(State.FAILED).withTaskId(taskId).withEndTimestamp(task.get().getUpdatedAt()));
                if (taskState.get().isSuccess()) {
                  metricRegistry.meter(getClass().getName() + ".succeeded").mark();
                } else {
                  metricRegistry.meter(getClass().getName() + ".failed").mark();
                }
              }
            }
          }

          for (ModuleBuild build : moduleBuildService.getByState(State.IN_PROGRESS)) {
            long age = System.currentTimeMillis() - build.getStartTimestamp().get();
            long maxAge = executorConfiguration.getBuildTimeoutMillis();
            if (age < TimeUnit.MINUTES.toMillis(1)) {
              continue;
            }

            String taskId = build.getTaskId().get();
            Optional taskHistory = singularityClient.getHistoryForTask(taskId);
            Optional completedTimestamp = completedTimestamp(taskHistory);
            if (!taskHistory.isPresent()) {
              LOG.warn("No task history found for taskId {}", taskId);
            } else if (completedTimestamp.isPresent()) {
              LOG.info("Failing build {} because taskId {} is done", build.getId().get(), taskId);
              moduleBuildService.update(build.withState(State.FAILED).withEndTimestamp(completedTimestamp.get()));
            } else if (age > maxAge) {
              LOG.info("Failing build {} because its age {} exceeded max of {}", build.getId().get(), age, maxAge);
              moduleBuildService.update(build.withState(State.FAILED).withEndTimestamp(System.currentTimeMillis()));
              singularityTaskKiller.killTask(build);
            }
          }
        }
      } catch (Throwable t) {
        LOG.error("Error checking for failed or lost tasks", t);
      }
    }

    private Optional completedTimestamp(Optional taskHistory) {
      if (!taskHistory.isPresent()) {
        return Optional.absent();
      }

      for (SingularityTaskHistoryUpdate taskUpdate : taskHistory.get().getTaskUpdates()) {
        if (taskUpdate.getTaskState().isDone()) {
          return Optional.of(taskUpdate.getTimestamp());
        }
      }

      return Optional.absent();
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy