package com.hubspot.blazar.visitor; import java.util.Set; import javax.inject.Inject; import javax.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import com.hubspot.blazar.base.InterProjectBuild; import com.hubspot.blazar.base.ModuleBuild; import com.hubspot.blazar.base.RepositoryBuild; import com.hubspot.blazar.base.visitor.InterProjectBuildVisitor; import com.hubspot.blazar.base.visitor.ModuleBuildVisitor; import com.hubspot.blazar.base.visitor.RepositoryBuildVisitor; import com.hubspot.blazar.data.service.InterProjectBuildService; import com.hubspot.blazar.data.service.ModuleBuildService; import com.hubspot.blazar.data.service.RepositoryBuildService; import com.hubspot.blazar.exception.NonRetryableBuildException; @Singleton public class BuildEventDispatcher { private static final Logger LOG = LoggerFactory.getLogger(BuildEventDispatcher.class); private final RepositoryBuildService repositoryBuildService; private final ModuleBuildService moduleBuildService; private final Set<RepositoryBuildVisitor> repositoryVisitors; private final InterProjectBuildService interProjectBuildService; private final Set<InterProjectBuildVisitor> interProjectBuildVisitors; private final Set<ModuleBuildVisitor> moduleVisitors; @Inject public BuildEventDispatcher(RepositoryBuildService repositoryBuildService, ModuleBuildService moduleBuildService, InterProjectBuildService interProjectBuildService, Set<RepositoryBuildVisitor> repositoryVisitors, Set<InterProjectBuildVisitor> interProjectBuildVisitors, Set<ModuleBuildVisitor> moduleVisitors, EventBus eventBus) { this.repositoryBuildService = repositoryBuildService; this.moduleBuildService = moduleBuildService; this.interProjectBuildService = interProjectBuildService; this.repositoryVisitors = repositoryVisitors; this.interProjectBuildVisitors = interProjectBuildVisitors; this.moduleVisitors = moduleVisitors; eventBus.register(this); } @Subscribe public void dispatch(RepositoryBuild build) throws Exception { Optional<RepositoryBuild> current = repositoryBuildService.get(build.getId().get()); if (!current.isPresent()) { LOG.warn("No repository build {}, ignoring event", build.getId().get()); return; } else if (current.get().getState() != build.getState()) { LOG.warn("Ignoring stale event with state {} for repository build {}, current state is {}", build.getState(), build.getId().get(), current.get().getState()); return; } else { build = current.get(); } try { for (RepositoryBuildVisitor visitor : repositoryVisitors) { visitor.visit(build); } } catch (NonRetryableBuildException e) { if (build.getState().isComplete()) { LOG.error("Caught error while processing completed build {} will not fail the build because it is already complete.", build, e); } else { LOG.warn("Failing build {}", build.getId().get(), e); repositoryBuildService.fail(build); } } } @Subscribe public void dispatch(ModuleBuild build) throws Exception { ModuleBuild current = moduleBuildService.get(build.getId().get()).get(); if (!matchingState(current.getState(), build.getState())) { LOG.warn("Ignoring stale event with state {} for module build {}, current state is {}", build.getState(), build.getId().get(), current.getState()); return; } else { build = current; } try { for (ModuleBuildVisitor visitor : moduleVisitors) { visitor.visit(build); } } catch (NonRetryableBuildException e) { if (build.getState().isComplete()) { LOG.error("Caught error while processing completed build {} will not fail the build because it is already complete.", build, e); } else { LOG.warn("Failing build {}", build.getId().get(), e); moduleBuildService.fail(build); } } } private boolean matchingState(ModuleBuild.State current, ModuleBuild.State other) { if (current == other) { return true; } else if (current.isComplete()) { return false; } else { return current.getSimpleState() == other.getSimpleState(); } } @Subscribe public void dispatch(InterProjectBuild build) throws Exception { InterProjectBuild current = interProjectBuildService.getWithId(build.getId().get()).get(); if (current.getState() != build.getState()) { LOG.warn("Ignoring stale event with state {} for InterProjectBuild {}, current state is {}", build.getState(), build.getId().get(), current.getState()); return; } else { build = current; } try { for (InterProjectBuildVisitor visitor : interProjectBuildVisitors) { visitor.visit(build); } } catch (NonRetryableBuildException e) { LOG.warn("Got non Retryable Exception in InterProjectBuild {}, marking as Finished", build.getId().get()); interProjectBuildService.finish(InterProjectBuild.getFinishedBuild(build, InterProjectBuild.State.FAILED)); } } }