Skip to content

Commit

Permalink
Merge pull request #99 from ls1intum/develop
Browse files Browse the repository at this point in the history
LocalCI Metrics
  • Loading branch information
valentin-boehm authored Jan 10, 2024
2 parents 1f21f5b + 8f4b3a8 commit 04c3874
Show file tree
Hide file tree
Showing 27 changed files with 437 additions and 19 deletions.
89 changes: 89 additions & 0 deletions src/main/java/de/tum/cit/ase/domain/LocalCIStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package de.tum.cit.ase.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;

@Entity
@Table(name = "local_ci_status")
public class LocalCIStatus {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "is_finished")
private boolean isFinished;

@Column(name = "queued_jobs")
private int queuedJobs;

@Column(name = "total_jobs")
private int totalJobs;

@Column(name = "time_in_minutes")
private int timeInMinutes;

@Column(name = "avg_jobs_per_minute")
private double avgJobsPerMinute;

@OneToOne
@JoinColumn(name = "simulation_run_id", nullable = false)
@JsonIgnore
private SimulationRun simulationRun;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public boolean isFinished() {
return isFinished;
}

public void setFinished(boolean finished) {
isFinished = finished;
}

public int getQueuedJobs() {
return queuedJobs;
}

public void setQueuedJobs(int queuedJobs) {
this.queuedJobs = queuedJobs;
}

public int getTotalJobs() {
return totalJobs;
}

public void setTotalJobs(int totalJobs) {
this.totalJobs = totalJobs;
}

public int getTimeInMinutes() {
return timeInMinutes;
}

public void setTimeInMinutes(int timeInMinutes) {
this.timeInMinutes = timeInMinutes;
}

public double getAvgJobsPerMinute() {
return avgJobsPerMinute;
}

public void setAvgJobsPerMinute(double avgJobsPerMinute) {
this.avgJobsPerMinute = avgJobsPerMinute;
}

public SimulationRun getSimulationRun() {
return simulationRun;
}

public void setSimulationRun(SimulationRun simulationRun) {
this.simulationRun = simulationRun;
}
}
11 changes: 11 additions & 0 deletions src/main/java/de/tum/cit/ase/domain/SimulationRun.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ public class SimulationRun {
@OneToMany(cascade = CascadeType.REMOVE, mappedBy = "simulationRun")
private Set<LogMessage> logMessages;

@OneToOne(cascade = CascadeType.REMOVE, mappedBy = "simulationRun", fetch = FetchType.EAGER)
private LocalCIStatus localCIStatus;

@Transient
private ArtemisAccountDTO adminAccount;

Expand Down Expand Up @@ -113,6 +116,14 @@ public void setEndDateTime(ZonedDateTime endDateTime) {
this.endDateTime = endDateTime;
}

public LocalCIStatus getLocalCIStatus() {
return localCIStatus;
}

public void setLocalCIStatus(LocalCIStatus localCIStatus) {
this.localCIStatus = localCIStatus;
}

public enum Status {
QUEUED,
RUNNING,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package de.tum.cit.ase.repository;

import de.tum.cit.ase.domain.LocalCIStatus;
import jakarta.transaction.Transactional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

@Repository
public interface LocalCIStatusRepository extends JpaRepository<LocalCIStatus, Long> {
@Modifying
@Transactional
@Query(value = "delete from LocalCIStatus status where status.isFinished = false")
void deleteAllNotFinished();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import de.tum.cit.ase.domain.SimulationRun;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Expand All @@ -16,5 +17,5 @@ public interface SimulationRunRepository extends JpaRepository<SimulationRun, Lo
List<SimulationRun> findAllBySimulationId(@Param("simulationId") long simulationId);

@Query(value = "select run from SimulationRun run left join fetch run.stats s left join fetch run.logMessages l where run.id = :#{#id}")
SimulationRun findByIdWithStatsAndLogMessages(long id);
Optional<SimulationRun> findByIdWithStatsAndLogMessages(long id);
}
72 changes: 72 additions & 0 deletions src/main/java/de/tum/cit/ase/service/LocalCIStatusService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package de.tum.cit.ase.service;

import de.tum.cit.ase.domain.LocalCIStatus;
import de.tum.cit.ase.domain.SimulationRun;
import de.tum.cit.ase.repository.LocalCIStatusRepository;
import de.tum.cit.ase.service.artemis.interaction.SimulatedArtemisAdmin;
import de.tum.cit.ase.web.websocket.SimulationWebsocketService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class LocalCIStatusService {

private final Logger log = LoggerFactory.getLogger(LocalCIStatusService.class);
private final LocalCIStatusRepository localCIStatusRepository;
private final SimulationWebsocketService websocketService;

public LocalCIStatusService(LocalCIStatusRepository localCIStatusRepository, SimulationWebsocketService websocketService) {
this.localCIStatusRepository = localCIStatusRepository;
this.websocketService = websocketService;
cleanup();
}

public LocalCIStatus createLocalCIStatus(SimulationRun simulationRun) {
LocalCIStatus status = new LocalCIStatus();
status.setSimulationRun(simulationRun);
status.setFinished(false);
status.setAvgJobsPerMinute(0);
status.setQueuedJobs(0);
status.setTotalJobs(0);
status.setTimeInMinutes(0);
return localCIStatusRepository.save(status);
}

@Async
public void subscribeToLocalCIStatus(SimulationRun simulationRun, SimulatedArtemisAdmin admin, long courseId) {
log.info("Subscribing to local CI status for simulation run {}", simulationRun.getId());
LocalCIStatus status = createLocalCIStatus(simulationRun);

int numberOfQueuedJobs = admin.getBuildQueue(courseId).size();
status.setTotalJobs(numberOfQueuedJobs);
status.setQueuedJobs(numberOfQueuedJobs);
status = localCIStatusRepository.save(status);
websocketService.sendRunLocalCIUpdate(simulationRun.getId(), status);

do {
try {
Thread.sleep(1000 * 60);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
log.debug("Updating local CI status for simulation run {}", simulationRun.getId());
numberOfQueuedJobs = admin.getBuildQueue(courseId).size();
status.setQueuedJobs(numberOfQueuedJobs);
status.setTimeInMinutes(status.getTimeInMinutes() + 1);
status.setAvgJobsPerMinute((double) (status.getTotalJobs() - status.getQueuedJobs()) / status.getTimeInMinutes());
status = localCIStatusRepository.save(status);
websocketService.sendRunLocalCIUpdate(simulationRun.getId(), status);
} while (numberOfQueuedJobs > 0);
status.setFinished(true);
status = localCIStatusRepository.save(status);
websocketService.sendRunLocalCIUpdate(simulationRun.getId(), status);
log.info("Finished subscribing to local CI status for simulation run {}", simulationRun.getId());
}

private void cleanup() {
log.info("Cleaning up local CI status");
localCIStatusRepository.deleteAllNotFinished();
}
}
4 changes: 2 additions & 2 deletions src/main/java/de/tum/cit/ase/service/PrometheusService.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public List<MetricValue> getCpuUsageVcs(SimulationRun run) {
* @return A list of CPU usage values. An empty list if no Prometheus instance is configured for the CI system.
*/
public List<MetricValue> getCpuUsageCi(SimulationRun run) {
log.info("Getting CI CPU usage for {}", run);
log.debug("Getting CI CPU usage for {}", run);
var instance = artemisConfiguration.getPrometheusInstanceCi(run.getSimulation().getServer());
if (instance == null || instance.isBlank()) {
log.warn("No Prometheus instance configured for CI on {}", run.getSimulation().getServer());
Expand All @@ -94,7 +94,7 @@ public List<MetricValue> getCpuUsageCi(SimulationRun run) {
* @return The response from Prometheus.
*/
public QueryResponse executeQuery(String query, ZonedDateTime start, ZonedDateTime end) {
log.info("Querying Prometheus: {}", query);
log.debug("Querying Prometheus: {}", query);
if (webClient == null) {
setupWebclient();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ public class ArtemisConfiguration {
@Value("${artemis.local.prometheus-instances.ci}")
private String localPrometheusInstanceCi;

@Value("${artemis.local.is-local}")
private boolean localIsLocal;

@Value("${artemis.ts1.url}")
private String test1Url;

Expand All @@ -37,6 +40,9 @@ public class ArtemisConfiguration {
@Value("${artemis.ts1.prometheus-instances.ci}")
private String test1PrometheusInstanceCi;

@Value("${artemis.ts1.is-local}")
private boolean test1IsLocal;

@Value("${artemis.ts3.url}")
private String test3Url;

Expand All @@ -52,6 +58,9 @@ public class ArtemisConfiguration {
@Value("${artemis.ts3.prometheus-instances.ci}")
private String test3PrometheusInstanceCi;

@Value("${artemis.ts3.is-local}")
private boolean test3IsLocal;

@Value("${artemis.staging.url}")
private String stagingUrl;

Expand All @@ -67,6 +76,9 @@ public class ArtemisConfiguration {
@Value("${artemis.staging.prometheus-instances.ci}")
private String stagingPrometheusInstanceCi;

@Value("${artemis.staging.is-local}")
private boolean stagingIsLocal;

@Value("${artemis.staging2.url}")
private String staging2Url;

Expand All @@ -82,6 +94,9 @@ public class ArtemisConfiguration {
@Value("${artemis.staging2.prometheus-instances.ci}")
private String staging2PrometheusInstanceCi;

@Value("${artemis.staging2.is-local}")
private boolean staging2IsLocal;

@Value("${artemis.production.url}")
private String productionUrl;

Expand All @@ -97,6 +112,9 @@ public class ArtemisConfiguration {
@Value("${artemis.production.prometheus-instances.ci}")
private String productionPrometheusInstanceCi;

@Value("${artemis.production.is-local}")
private boolean productionIsLocal;

public String getUrl(ArtemisServer server) {
return switch (server) {
case LOCAL -> localUrl;
Expand Down Expand Up @@ -151,4 +169,15 @@ public String getPrometheusInstanceCi(ArtemisServer server) {
case PRODUCTION -> productionPrometheusInstanceCi;
};
}

public boolean getIsLocal(ArtemisServer server) {
return switch (server) {
case LOCAL -> localIsLocal;
case TS1 -> test1IsLocal;
case TS3 -> test3IsLocal;
case STAGING -> stagingIsLocal;
case STAGING2 -> staging2IsLocal;
case PRODUCTION -> productionIsLocal;
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.reactivex.rxjava3.core.Scheduler;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -463,4 +464,14 @@ public void deleteExam(long courseId, long examId) {
.toBodilessEntity()
.block();
}

public List<DomainObject> getBuildQueue(long courseId) {
return webClient
.get()
.uri(uriBuilder -> uriBuilder.pathSegment("api", "build-job-queue", "queued", String.valueOf(courseId)).build())
.retrieve()
.bodyToFlux(DomainObject.class)
.collectList()
.block();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public SimulationRun getSimulationRun(long id) {
}

public SimulationRun getSimulationRunWithStatsAndLogs(long id) {
return simulationRunRepository.findByIdWithStatsAndLogMessages(id);
return simulationRunRepository.findByIdWithStatsAndLogMessages(id).orElseThrow();
}

public void deleteSimulation(long id) {
Expand Down Expand Up @@ -166,7 +166,7 @@ public void cancelActiveRun(long runId) {
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
run = simulationRunRepository.findById(runId).orElseThrow();
run = simulationRunRepository.findByIdWithStatsAndLogMessages(runId).orElseThrow();

run.setStatus(SimulationRun.Status.CANCELLED);
run.setEndDateTime(now());
Expand Down
Loading

0 comments on commit 04c3874

Please sign in to comment.