Skip to content

Commit

Permalink
ADM-733[backend]refactor: divide AsyncMetricsDataHandler from AsyncRe…
Browse files Browse the repository at this point in the history
…portRequestHandler
  • Loading branch information
BoBoDai committed Jan 18, 2024
1 parent bcc3f5b commit ce9c2a4
Show file tree
Hide file tree
Showing 11 changed files with 119 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import com.google.gson.Gson;
import heartbeat.exception.BaseException;
import heartbeat.handler.base.AsyncDataBaseHandler;
import heartbeat.handler.base.AsyncExceptionDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

import static heartbeat.handler.FIleType.ERROR;
import static heartbeat.handler.base.FIleType.ERROR;

@Log4j2
@Component
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package heartbeat.handler;

import com.google.gson.Gson;
import heartbeat.controller.report.dto.response.MetricsDataCompleted;
import heartbeat.exception.GenerateReportException;
import heartbeat.handler.base.AsyncDataBaseHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static heartbeat.handler.base.FIleType.METRICS_DATA_COMPLETED;
import static heartbeat.service.report.scheduler.DeleteExpireCSVScheduler.EXPORT_CSV_VALIDITY_TIME;

@Log4j2
@Component
@RequiredArgsConstructor
public class AsyncMetricsDataHandler extends AsyncDataBaseHandler {

private final Map<String, MetricsDataCompleted> metricsDataCompletedMap = new ConcurrentHashMap<>();

public void putMetricsDataCompleted(String timeStamp, MetricsDataCompleted metricsDataCompleted) {
createDirToConvertData(METRICS_DATA_COMPLETED);
creatFileByType(METRICS_DATA_COMPLETED, timeStamp, new Gson().toJson(metricsDataCompleted));
metricsDataCompletedMap.put(timeStamp, metricsDataCompleted);
}

public MetricsDataCompleted getMetricsDataCompleted(String timeStamp) {
return metricsDataCompletedMap.get(timeStamp);
}

public boolean isReportReady(String timeStamp) {
MetricsDataCompleted metricsDataCompleted = getMetricsDataCompleted(timeStamp);
if (metricsDataCompleted == null) {
throw new GenerateReportException("Failed to locate the report using this report ID.");
}

List<Boolean> metricsReady = Stream
.of(metricsDataCompleted.boardMetricsCompleted(), metricsDataCompleted.pipelineMetricsCompleted(),
metricsDataCompleted.sourceControlMetricsCompleted())
.filter(Objects::nonNull)
.toList();

return metricsReady.stream().allMatch(Boolean::valueOf);
}

public void deleteExpireMetricsDataCompleted(long currentTimeStamp) {
long exportTime = currentTimeStamp - EXPORT_CSV_VALIDITY_TIME;
Set<String> keys = metricsDataCompletedMap.keySet()
.stream()
.filter(timeStamp -> Long.parseLong(timeStamp) < exportTime)
.collect(Collectors.toSet());
metricsDataCompletedMap.keySet().removeAll(keys);
}

}
Original file line number Diff line number Diff line change
@@ -1,33 +1,19 @@
package heartbeat.handler;

import com.google.gson.Gson;
import heartbeat.controller.report.dto.response.MetricsDataCompleted;
import heartbeat.controller.report.dto.response.ReportResponse;
import heartbeat.exception.GenerateReportException;
import heartbeat.handler.base.AsyncDataBaseHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static heartbeat.handler.FIleType.METRICS_DATA_COMPLETED;
import static heartbeat.handler.FIleType.REPORT;
import static heartbeat.service.report.scheduler.DeleteExpireCSVScheduler.EXPORT_CSV_VALIDITY_TIME;
import static heartbeat.handler.base.FIleType.REPORT;

@Log4j2
@Component
@RequiredArgsConstructor
public class AsyncReportRequestHandler extends AsyncDataBaseHandler {

private final Map<String, MetricsDataCompleted> metricsDataCompletedMap = new ConcurrentHashMap<>();

public void putReport(String reportId, ReportResponse e) {
createDirToConvertData(REPORT);
creatFileByType(REPORT, reportId, new Gson().toJson(e));
Expand All @@ -37,42 +23,8 @@ public ReportResponse getReport(String reportId) {
return readFileByType(REPORT, reportId, ReportResponse.class);
}

public void putMetricsDataCompleted(String timeStamp, MetricsDataCompleted metricsDataCompleted) {
createDirToConvertData(METRICS_DATA_COMPLETED);
creatFileByType(METRICS_DATA_COMPLETED, timeStamp, new Gson().toJson(metricsDataCompleted));
metricsDataCompletedMap.put(timeStamp, metricsDataCompleted);
}

public MetricsDataCompleted getMetricsDataCompleted(String timeStamp) {
return metricsDataCompletedMap.get(timeStamp);
}

public boolean isReportReady(String timeStamp) {
MetricsDataCompleted metricsDataCompleted = getMetricsDataCompleted(timeStamp);
if (metricsDataCompleted == null) {
throw new GenerateReportException("Failed to locate the report using this report ID.");
}

List<Boolean> metricsReady = Stream
.of(metricsDataCompleted.boardMetricsCompleted(), metricsDataCompleted.pipelineMetricsCompleted(),
metricsDataCompleted.sourceControlMetricsCompleted())
.filter(Objects::nonNull)
.toList();

return metricsReady.stream().allMatch(Boolean::valueOf);
}

public void deleteExpireReport(long currentTimeStamp) {
deleteExpireFileByType(REPORT, currentTimeStamp);
}

public void deleteExpireMetricsDataCompleted(long currentTimeStamp) {
long exportTime = currentTimeStamp - EXPORT_CSV_VALIDITY_TIME;
Set<String> keys = metricsDataCompletedMap.keySet()
.stream()
.filter(timeStamp -> Long.parseLong(timeStamp) < exportTime)
.collect(Collectors.toSet());
metricsDataCompletedMap.keySet().removeAll(keys);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.google.gson.stream.JsonReader;
import heartbeat.exception.FileIOException;
import heartbeat.exception.GenerateReportException;
import heartbeat.handler.FIleType;
import lombok.extern.log4j.Log4j2;
import org.springframework.util.ObjectUtils;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package heartbeat.handler;
package heartbeat.handler.base;

import heartbeat.exception.BaseException;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package heartbeat.handler;
package heartbeat.handler.base;

import lombok.AllArgsConstructor;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import heartbeat.exception.RequestFailedException;
import heartbeat.exception.ServiceUnavailableException;
import heartbeat.handler.AsyncExceptionHandler;
import heartbeat.handler.AsyncMetricsDataHandler;
import heartbeat.handler.AsyncReportRequestHandler;
import heartbeat.service.board.jira.JiraColumnResult;
import heartbeat.service.board.jira.JiraService;
Expand Down Expand Up @@ -122,6 +123,8 @@ public class GenerateReporterService {

private final AsyncReportRequestHandler asyncReportRequestHandler;

private final AsyncMetricsDataHandler asyncMetricsDataHandler;

private final AsyncExceptionHandler asyncExceptionHandler;

private static StoryPointsAndCycleTimeRequest buildStoryPointsAndCycleTimeRequest(JiraBoardSetting jiraBoardSetting,
Expand Down Expand Up @@ -655,11 +658,11 @@ public void saveReporterInHandler(ReportResponse reportContent, String reportId)

public void initializeMetricsDataCompletedInHandler(String timeStamp, List<String> metrics) {
MetricsDataCompleted metricsStatus = getMetricsStatus(metrics, Boolean.FALSE);
MetricsDataCompleted previousMetricsCompleted = asyncReportRequestHandler.getMetricsDataCompleted(timeStamp);
MetricsDataCompleted previousMetricsCompleted = asyncMetricsDataHandler.getMetricsDataCompleted(timeStamp);
MetricsDataCompleted isMetricsDataCompleted = createMetricsDataCompleted(metricsStatus.boardMetricsCompleted(),
metricsStatus.sourceControlMetricsCompleted(), metricsStatus.pipelineMetricsCompleted(),
previousMetricsCompleted);
asyncReportRequestHandler.putMetricsDataCompleted(timeStamp, isMetricsDataCompleted);
asyncMetricsDataHandler.putMetricsDataCompleted(timeStamp, isMetricsDataCompleted);
}

private MetricsDataCompleted createMetricsDataCompleted(Boolean boardMetricsCompleted,
Expand Down Expand Up @@ -690,7 +693,7 @@ private Boolean getCompletedValue(Boolean previousCompletedValue, Boolean newCom

public void updateMetricsDataCompletedInHandler(String timeStamp, List<String> metrics) {
MetricsDataCompleted metricsStatus = getMetricsStatus(metrics, Boolean.TRUE);
MetricsDataCompleted previousMetricsCompleted = asyncReportRequestHandler.getMetricsDataCompleted(timeStamp);
MetricsDataCompleted previousMetricsCompleted = asyncMetricsDataHandler.getMetricsDataCompleted(timeStamp);
if (previousMetricsCompleted == null) {
log.error("Failed to update metrics data completed through this timestamp.");
throw new GenerateReportException("Failed to update metrics data completed through this timestamp.");
Expand All @@ -704,7 +707,7 @@ public void updateMetricsDataCompletedInHandler(String timeStamp, List<String> m
checkCurrentMetricsCompletedState(metricsStatus.sourceControlMetricsCompleted(),
previousMetricsCompleted.sourceControlMetricsCompleted()))
.build();
asyncReportRequestHandler.putMetricsDataCompleted(timeStamp, metricsDataCompleted);
asyncMetricsDataHandler.putMetricsDataCompleted(timeStamp, metricsDataCompleted);
}

private Boolean checkCurrentMetricsCompletedState(Boolean exist, Boolean previousValue) {
Expand Down Expand Up @@ -804,7 +807,7 @@ public boolean checkGenerateReportIsDone(String reportTimeStamp) {
if (validateExpire(System.currentTimeMillis(), Long.parseLong(reportTimeStamp))) {
throw new GenerateReportException("Failed to get report due to report time expires");
}
return asyncReportRequestHandler.isReportReady(reportTimeStamp);
return asyncMetricsDataHandler.isReportReady(reportTimeStamp);
}

private ErrorInfo handleAsyncExceptionAndGetErrorInfo(BaseException exception) {
Expand Down Expand Up @@ -863,7 +866,7 @@ public ReportResponse getComposedReportResponse(String reportId, boolean isRepor
ReportResponse boardReportResponse = getReportFromHandler(IdUtil.getBoardReportId(reportId));
ReportResponse doraReportResponse = getReportFromHandler(IdUtil.getPipelineReportId(reportId));
ReportResponse codebaseReportResponse = getReportFromHandler(IdUtil.getSourceControlReportId(reportId));
MetricsDataCompleted metricsDataCompleted = asyncReportRequestHandler.getMetricsDataCompleted(reportId);
MetricsDataCompleted metricsDataCompleted = asyncMetricsDataHandler.getMetricsDataCompleted(reportId);
ReportResponse response = Optional.ofNullable(boardReportResponse).orElse(doraReportResponse);
ReportMetricsError reportMetricsError = getReportErrorAndHandleAsyncException(reportId);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package heartbeat.service.report.scheduler;

import heartbeat.handler.AsyncMetricsDataHandler;
import heartbeat.handler.AsyncReportRequestHandler;
import heartbeat.service.report.GenerateReporterService;
import heartbeat.handler.AsyncExceptionHandler;
Expand All @@ -26,13 +27,15 @@ public class DeleteExpireCSVScheduler {

private final AsyncExceptionHandler asyncExceptionHandler;

private final AsyncMetricsDataHandler asyncMetricsDataHandler;

@Scheduled(fixedRate = DELETE_INTERVAL_IN_MINUTES, timeUnit = TimeUnit.MINUTES)
public void triggerBatchDelete() {
long currentTimeStamp = System.currentTimeMillis();
log.info("Start to delete expired CSV files, currentTimeStamp: {}", currentTimeStamp);
generateReporterService.deleteExpireCSV(currentTimeStamp, new File("./csv/"));
asyncReportRequestHandler.deleteExpireReport(currentTimeStamp);
asyncReportRequestHandler.deleteExpireMetricsDataCompleted(currentTimeStamp);
asyncMetricsDataHandler.deleteExpireMetricsDataCompleted(currentTimeStamp);
asyncExceptionHandler.deleteExpireException(currentTimeStamp);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ class AsyncReportRequestHandlerTest {
@InjectMocks
AsyncReportRequestHandler asyncReportRequestHandler;

@InjectMocks
AsyncMetricsDataHandler asyncMetricsDataHandler;

@AfterEach
void afterEach() {
new File(APP_OUTPUT_REPORT).delete();
Expand Down Expand Up @@ -72,23 +75,23 @@ void shouldDeleteMetricsDataReadyWhenExpireIsExpire() {
String currentTime = Long.toString(currentTimeMillis);
String expireTime = Long.toString(currentTimeMillis - 1900000L);
MetricsDataCompleted metricsDataCompleted = MetricsDataCompleted.builder().boardMetricsCompleted(false).build();
asyncReportRequestHandler.putMetricsDataCompleted(currentTime, metricsDataCompleted);
asyncReportRequestHandler.putMetricsDataCompleted(expireTime, metricsDataCompleted);
asyncMetricsDataHandler.putMetricsDataCompleted(currentTime, metricsDataCompleted);
asyncMetricsDataHandler.putMetricsDataCompleted(expireTime, metricsDataCompleted);

asyncReportRequestHandler.deleteExpireMetricsDataCompleted(currentTimeMillis);
asyncMetricsDataHandler.deleteExpireMetricsDataCompleted(currentTimeMillis);

assertNull(asyncReportRequestHandler.getMetricsDataCompleted(expireTime));
assertNotNull(asyncReportRequestHandler.getMetricsDataCompleted(currentTime));
assertNull(asyncMetricsDataHandler.getMetricsDataCompleted(expireTime));
assertNotNull(asyncMetricsDataHandler.getMetricsDataCompleted(currentTime));
}

@Test
void shouldGetAsyncMetricsDataReadyWhenPuttingMetricsReadyIntoAsyncReportRequestHandler() {
long currentTimeMillis = System.currentTimeMillis();
String currentTime = Long.toString(currentTimeMillis);
MetricsDataCompleted metricsDataCompleted = MetricsDataCompleted.builder().boardMetricsCompleted(false).build();
asyncReportRequestHandler.putMetricsDataCompleted(currentTime, metricsDataCompleted);
asyncMetricsDataHandler.putMetricsDataCompleted(currentTime, metricsDataCompleted);

assertNotNull(asyncReportRequestHandler.getMetricsDataCompleted(currentTime));
assertNotNull(asyncMetricsDataHandler.getMetricsDataCompleted(currentTime));
}

@Test
Expand All @@ -97,7 +100,7 @@ void shouldThrowGenerateReportExceptionWhenPreviousMetricsDataReadyIsNull() {
String currentTime = Long.toString(currentTimeMillis);

Exception exception = assertThrows(GenerateReportException.class,
() -> asyncReportRequestHandler.isReportReady(currentTime));
() -> asyncMetricsDataHandler.isReportReady(currentTime));
assertEquals("Failed to locate the report using this report ID.", exception.getMessage());
}

Expand All @@ -110,9 +113,9 @@ void shouldReturnFalseWhenExistFalseValue() {
.sourceControlMetricsCompleted(false)
.pipelineMetricsCompleted(null)
.build();
asyncReportRequestHandler.putMetricsDataCompleted(currentTime, metricsDataCompleted);
asyncMetricsDataHandler.putMetricsDataCompleted(currentTime, metricsDataCompleted);

boolean reportReady = asyncReportRequestHandler.isReportReady(currentTime);
boolean reportReady = asyncMetricsDataHandler.isReportReady(currentTime);

assertFalse(reportReady);
}
Expand All @@ -126,9 +129,9 @@ void shouldReturnTrueWhenNotExistFalseValue() {
.sourceControlMetricsCompleted(null)
.pipelineMetricsCompleted(true)
.build();
asyncReportRequestHandler.putMetricsDataCompleted(currentTime, metricsDataCompleted);
asyncMetricsDataHandler.putMetricsDataCompleted(currentTime, metricsDataCompleted);

boolean reportReady = asyncReportRequestHandler.isReportReady(currentTime);
boolean reportReady = asyncMetricsDataHandler.isReportReady(currentTime);

assertTrue(reportReady);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package heartbeat.service.report;

import heartbeat.handler.AsyncExceptionHandler;
import heartbeat.handler.AsyncMetricsDataHandler;
import heartbeat.handler.AsyncReportRequestHandler;
import heartbeat.service.report.scheduler.DeleteExpireCSVScheduler;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -30,6 +31,9 @@ class DeleteExpireCSVSchedulerTest {
@Mock
private AsyncReportRequestHandler asyncReportRequestHandler;

@Mock
private AsyncMetricsDataHandler asyncMetricsDataHandler;

@Mock
private AsyncExceptionHandler asyncExceptionHandler;

Expand Down
Loading

0 comments on commit ce9c2a4

Please sign in to comment.