Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,27 +47,55 @@ public void recalculateStatus(
this.actualRequestsPerSecond = actualRequestsPerSecond;
this.idealRequestsPerSecond = idealRequestsPerSecond;

var newStatus = this.getNewAbsoluteStatus();
LOGGER.trace(
"Current status is {} and possible new Status is {}.",
currentStatus, newStatus
);
if (newStatus.isBetterThen(currentStatus)) {
this.lowerStatusByOne();
} else {
this.setActualStatus(newStatus);
}
this.changeStatusAccordingToExpectedStatus(currentStatus);

LOGGER.debug("New Status is {}.", this.getStatus());
});
}

private void changeStatusAccordingToExpectedStatus(ApiRateLimitStatus currentStatus) {
var idealNewStatus = this.getNewAbsoluteStatus();

var statusComparison = idealNewStatus.compareTo(currentStatus);
if (statusComparison > 0) {
this.lowerStatusByOne();
} else if (statusComparison < 0) {
this.raiseStatusByOne();
}

logStatusChange(currentStatus, idealNewStatus);
}

private void logStatusChange(
ApiRateLimitStatus oldStatus,
ApiRateLimitStatus idealNewStatus
) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(
"Status has been recalculated with actual {} / ideal {} and would ideally become {}",
String.format("%.2f", this.actualRequestsPerSecond),
String.format("%.2f", this.idealRequestsPerSecond),
idealNewStatus
);
LOGGER.info(
"Status will instead be changed from [{}] to {}.",
oldStatus, this.getStatus()
);
}
}

public void lowerStatusByOne() {
this.status.ifPresent(currentStatus ->
this.setActualStatus(currentStatus.getNextBest())
);
}

public void raiseStatusByOne() {
this.status.ifPresent(currentStatus ->
this.setActualStatus(currentStatus.getNextWorst())
);
}

public ApiRateLimitStatus getNewAbsoluteStatus() {
ApiRateLimitStatus newStatus;
if (this.idealRequestsPerSecond * this.goodLimit >= this.actualRequestsPerSecond) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package be.xplore.githubmetrics.domain.apistate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.function.IntUnaryOperator;

public enum ApiRateLimitStatus {
CRITICAL, WARNING, CONCERNING, GOOD, OK;

private static final Logger LOGGER = LoggerFactory.getLogger(ApiRateLimitStatus.class);

public boolean isCritical() {
return this.equals(CRITICAL);
}
Expand All @@ -25,21 +23,26 @@ public boolean isGoodOrWorse() {
}

public ApiRateLimitStatus getNextBest() {
return switch (this) {
case CRITICAL -> WARNING;
case WARNING -> CONCERNING;
case CONCERNING -> GOOD;
case GOOD, OK -> OK;
};
}

public boolean isBetterThen(ApiRateLimitStatus other) {
var better = this.ordinal() > other.ordinal();
LOGGER.debug(
"The status {} is better then the status {}: {}",
this, other, better
return this.newStatus(ordinal -> ordinal + 1);
}

public ApiRateLimitStatus getNextWorst() {
return this.newStatus(ordinal -> ordinal - 1);
}

private ApiRateLimitStatus newStatus(IntUnaryOperator function) {
var newStatus = Math.clamp(
function.applyAsInt(this.ordinal()), min().ordinal(), max().ordinal()
);
return better;
return values()[newStatus];
}

public ApiRateLimitStatus max() {
return Arrays.stream(values()).max(ApiRateLimitStatus::compareTo).orElseThrow();
}

public ApiRateLimitStatus min() {
return Arrays.stream(values()).min(ApiRateLimitStatus::compareTo).orElseThrow();
}
}

Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package be.xplore.githubmetrics.domain.apistate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class GetCurrentApiRateLimitStateUseCase {

private static final Logger LOGGER = LoggerFactory.getLogger(GetCurrentApiRateLimitStateUseCase.class);
private final ApiRateLimitStateQueryPort apiRateLimitStateQueryPort;

public GetCurrentApiRateLimitStateUseCase(
Expand All @@ -14,6 +17,7 @@ public GetCurrentApiRateLimitStateUseCase(
}

public ApiRateLimitState getCurrentApiRateLimitState() {
LOGGER.debug("Exporting current Api rate limit state");
return this.apiRateLimitStateQueryPort.getCurrentApiRateLimitState();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public GetAllJobsOfLastDayUseCase(
public List<Job> getAllJobsOfLastDay() {
List<WorkflowRun> workflowRuns
= getAllWorkflowRunsOfLastDayUseCase.getAllWorkflowRunsOfLastDay();
LOGGER.info("Exporting Jobs of {} workflow runs.", workflowRuns.size());
LOGGER.debug("Exporting Jobs of {} workflow runs.", workflowRuns.size());
return workflowRuns.stream().map(
jobsQuery::getAllJobsForWorkflowRun
).flatMap(List::stream).toList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public GetAllPullRequestsUseCase(

public List<PullRequest> getAllPullRequests() {
List<Repository> repositories = repositoriesQuery.getAllRepositories();
LOGGER.info("Exporting pull requests for {} repositories.", repositories.size());
LOGGER.debug("Exporting pull requests for {} repositories.", repositories.size());
return repositories.stream().map(
pullRequestQuery::getAllPullRequestsForRepository
).flatMap(List::stream).toList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public GetAllRepositoriesUseCase(RepositoriesQueryPort repositoriesQueryPort) {
}

public List<Repository> getAllRepositories() {
LOGGER.info("Exporting all available Repositories.");
LOGGER.debug("Exporting all available Repositories.");
return this.repositoriesQueryPort.getAllRepositories();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public GetAllSelfHostedRunnersUseCase(

public List<SelfHostedRunner> getAllSelfHostedRunners() {
var repositories = this.repositoriesQuery.getAllRepositories();
LOGGER.info(
LOGGER.debug(
"Exporting self hosted runners for organization and {} repositories",
repositories.size()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

import be.xplore.githubmetrics.domain.repository.RepositoriesQueryPort;
import be.xplore.githubmetrics.domain.repository.Repository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class GetActiveWorkflowRunsUseCase {

private static final Logger LOGGER = LoggerFactory.getLogger(GetActiveWorkflowRunsUseCase.class);
private final RepositoriesQueryPort repositoriesQuery;
private final ActiveWorkflowRunsQueryPort activeWorkflowRunsQuery;

Expand All @@ -22,6 +25,10 @@ public GetActiveWorkflowRunsUseCase(

public List<WorkflowRun> getActiveWorkflowRuns() {
List<Repository> repositories = repositoriesQuery.getAllRepositories();
LOGGER.debug(
"Exporting active workflow runs for {} repositories.",
repositories.size()
);
return repositories.stream().map(
activeWorkflowRunsQuery::getActiveWorkflowRuns
).flatMap(List::stream).toList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public GetAllWorkflowRunBuildTimesOfLastDayUseCase(
public List<WorkflowRun> getAllWorkflowRunBuildTime() {
List<WorkflowRun> workflowRuns
= getAllWorkflowRunsOfLastDayUseCase.getAllWorkflowRunsOfLastDay();
LOGGER.info("Exporting build times for {} workflow runs.", workflowRuns.size());
LOGGER.debug("Exporting build times for {} workflow runs.", workflowRuns.size());
workflowRuns.forEach(workflowRun ->
workflowRun.setBuildTime(
workflowRunBuildTimesQueryPort.getWorkflowRunBuildTimes(workflowRun)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public GetAllWorkflowRunsOfLastDayUseCase(

public List<WorkflowRun> getAllWorkflowRunsOfLastDay() {
List<Repository> repositories = repositoriesQuery.getAllRepositories();
LOGGER.info(
LOGGER.debug(
"Exporting workflow runs of last day for {} repositories.",
repositories.size()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

class ApiStateTests {
Expand All @@ -29,38 +30,63 @@ private ApiRateLimitStatus getStatus() {
return this.state.getStatus().get();
}

private ApiRateLimitStatus getAbsNewStatus() {
return this.state.getNewAbsoluteStatus();
}

@Test
void drasticRequestRatioWorseningShouldOnlyWorsenStatusByOne() {
this.state.recalculateStatus(2, 1);
assertEquals(ApiRateLimitStatus.GOOD, getStatus());
}

@Test
void consistentRatioWorseningShouldSlowlyIncreaseStatus() {
this.state.recalculateStatus(2, 1);
assertEquals(ApiRateLimitStatus.GOOD, getStatus());
this.state.recalculateStatus(2, 1);
assertEquals(ApiRateLimitStatus.CONCERNING, getStatus());
this.state.recalculateStatus(2, 1);
assertEquals(ApiRateLimitStatus.WARNING, getStatus());
this.state.recalculateStatus(2, 1);
assertEquals(ApiRateLimitStatus.CRITICAL, getStatus());
}

@Test
void actualToIdealRatioThatDoesntExceedGoodLimitShouldStayOk() {
this.state.recalculateStatus(GOOD_LIMIT, 1);
assertEquals(ApiRateLimitStatus.OK, getStatus());
assertEquals(ApiRateLimitStatus.OK, getAbsNewStatus());
}

@Test
void actualToIdealRatioThatDoesntExceedConcerningLimitShouldBecomeOk() {
this.state.recalculateStatus(CONCERNING_LIMIT, 1);
assertEquals(ApiRateLimitStatus.GOOD, getStatus());
assertEquals(ApiRateLimitStatus.GOOD, getAbsNewStatus());
}

@Test
void actualToIdealRatioThatDoesntExceedWarningLimitShouldBecomeConcerning() {
this.state.recalculateStatus(WARNING_LIMIT, 1);
assertEquals(ApiRateLimitStatus.CONCERNING, getStatus());
assertEquals(ApiRateLimitStatus.CONCERNING, getAbsNewStatus());
}

@Test
void actualToIdealRatioThatDoesntExceedCriticalLimitShouldBecomeConcerning() {
this.state.recalculateStatus(CRITICAL_LIMIT, 1);
assertEquals(ApiRateLimitStatus.WARNING, getStatus());
assertEquals(ApiRateLimitStatus.WARNING, getAbsNewStatus());
}

@Test
void actualToIdealRatioThatExceedsCriticalLimitShouldBecomeCritical() {
this.state.recalculateStatus(2, 1);
assertEquals(ApiRateLimitStatus.CRITICAL, getStatus());
assertEquals(ApiRateLimitStatus.CRITICAL, getAbsNewStatus());
}

@Test
void drasticRequestRatioImprovementShouldOnlyImproveStatusByOne() {
this.state.recalculateStatus(2, 1);
this.state.recalculateStatus(2, 1);
this.state.recalculateStatus(2, 1);
this.state.recalculateStatus(2, 1);
assertEquals(ApiRateLimitStatus.CRITICAL, getStatus());
this.state.recalculateStatus(GOOD_LIMIT, 1);
Expand All @@ -75,4 +101,43 @@ void stopRequestsAndGetResetFunctionShouldClearStatusAndAllowForReset() {
resetFn.run();
assertEquals(ApiRateLimitStatus.CRITICAL, getStatus());
}

@Test
void completelyStoppingRequestingShouldAlwaysCauseDataWaitToReturnTrue() {
this.state.stopRequestsAndGetResetFunction();

shouldWaitAndRaise(ApiRateLimitStatus.GOOD);
shouldWaitAndRaise(ApiRateLimitStatus.CONCERNING);
shouldWaitAndRaise(ApiRateLimitStatus.WARNING);
shouldWaitAndRaise(ApiRateLimitStatus.CONCERNING);
shouldWaitAndRaise(null);
}

@Test
void dataShouldWaitWhenActualStatusIsOnSameLevelAsLimit() {
shouldWaitAndRaise(ApiRateLimitStatus.OK);
shouldWaitAndRaise(ApiRateLimitStatus.GOOD);
shouldWaitAndRaise(ApiRateLimitStatus.CONCERNING);
shouldWaitAndRaise(ApiRateLimitStatus.WARNING);
shouldWaitAndRaise(ApiRateLimitStatus.CRITICAL);
}

@Test
void nullLimitShouldNeverAskDataToWait() {
shouldNotWaitAndRaise(null);
shouldNotWaitAndRaise(null);
shouldNotWaitAndRaise(null);
shouldNotWaitAndRaise(null);
shouldNotWaitAndRaise(null);
}

private void shouldNotWaitAndRaise(ApiRateLimitStatus status) {
assertFalse(this.state.shouldDataWait(status));
this.state.raiseStatusByOne();
}

private void shouldWaitAndRaise(ApiRateLimitStatus status) {
assertTrue(this.state.shouldDataWait(status));
this.state.raiseStatusByOne();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
Expand Down Expand Up @@ -48,12 +47,14 @@ private void conditionallyCacheEvict(ScheduledCacheEvictionPort port) {
var name = port.cacheName();

if (!port.freshDataCanWait()) {
LOGGER.debug("Evicting {}", name);
Optional.ofNullable(
this.cacheManager.getCache(name)
).ifPresent(Cache::clear);
).ifPresent(cache -> {
LOGGER.info("Evicting the cache with name: {}", name);
cache.clear();
});
} else {
LOGGER.debug("Did not evict {}", name);
LOGGER.info("Did not evict the cache with name: {}", name);
}
}

Expand Down
Loading