-
Notifications
You must be signed in to change notification settings - Fork 0
UPLUS-105 데이터 사용량 관측 시스템 RDB 구현 #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
24bc545
7fefbf0
8c89081
7bfdc66
140dc2f
5ae0679
bc4d7ac
0317cde
a4eac93
5d8f848
a6607f4
ba0dcea
316ef4a
5c98e60
208f44f
bc9f28f
4c2ff1c
12c1183
59322c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| // package com.project.rdb; | ||
| // | ||
| // import org.springframework.batch.core.Job; | ||
| // import org.springframework.batch.core.JobParameters; | ||
| // import org.springframework.batch.core.JobParametersBuilder; | ||
| // import org.springframework.batch.core.launch.JobLauncher; | ||
| // import org.springframework.boot.CommandLineRunner; | ||
| // import org.springframework.stereotype.Component; | ||
| // | ||
| // import lombok.RequiredArgsConstructor; | ||
| // | ||
| // @Component | ||
| // @RequiredArgsConstructor | ||
| // public class BatchJobRunner implements CommandLineRunner { | ||
| // | ||
| // private final JobLauncher jobLauncher; | ||
| // private final Job usageAggregationJob; | ||
| // private final Job usageNotificationJob; | ||
| // private final Job notificationSendJob; | ||
| // | ||
| // ////// @Override | ||
| // ////// public void run(String... args) throws Exception { | ||
| // ////// JobParameters params = new JobParametersBuilder() | ||
| // ////// .addString("fromTime", "2025-12-01T00:00:00") | ||
| // ////// .addString("toTime", "2025-12-31T11:59:59") | ||
| // ////// .addLong("run.id", System.currentTimeMillis()) | ||
| // ////// .toJobParameters(); | ||
| // ////// | ||
| // ////// jobLauncher.run(usageAggregationJob, params); | ||
| // ////// } | ||
| // //// | ||
| // ////// @Override | ||
| // ////// public void run(String... args) throws Exception { | ||
| // ////// | ||
| // ////// JobParameters params = new JobParametersBuilder() | ||
| // ////// // 월 요금제 Step용 | ||
| // ////// .addString("period", "202512") | ||
| // ////// // 일 요금제 Step용 | ||
| // ////// .addString("usageDate", "20251201") | ||
| // ////// .addLong("run.id", System.currentTimeMillis()) | ||
| // ////// .toJobParameters(); | ||
| // ////// | ||
| // ////// jobLauncher.run(usageNotificationJob, params); | ||
| // ////// } | ||
| // // | ||
| // @Override | ||
| // public void run(String... args) throws Exception { | ||
| // JobParameters params = | ||
| // new JobParametersBuilder() | ||
| // .addLong("runAt", System.currentTimeMillis()) // 중복 실행 방지 | ||
| // .toJobParameters(); | ||
| // | ||
| // jobLauncher.run(notificationSendJob, params); | ||
| // } | ||
| // } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,83 @@ | ||||||||||||||||||||||||||||||||||||||
| package com.project.rdb.batch.model; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import java.math.BigDecimal; | ||||||||||||||||||||||||||||||||||||||
| import java.math.RoundingMode; | ||||||||||||||||||||||||||||||||||||||
| import java.time.Duration; | ||||||||||||||||||||||||||||||||||||||
| import java.time.LocalDateTime; | ||||||||||||||||||||||||||||||||||||||
| import java.time.ZoneId; | ||||||||||||||||||||||||||||||||||||||
| import java.util.Objects; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import org.springframework.batch.core.ExitStatus; | ||||||||||||||||||||||||||||||||||||||
| import org.springframework.batch.core.JobExecution; | ||||||||||||||||||||||||||||||||||||||
| import org.springframework.batch.core.StepExecution; | ||||||||||||||||||||||||||||||||||||||
| import org.springframework.batch.core.StepExecutionListener; | ||||||||||||||||||||||||||||||||||||||
| import org.springframework.stereotype.Component; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||||||||||||||||||||||||||||||||||||
| import com.project.rdb.batch.model.entity.BatchExecutionReport; | ||||||||||||||||||||||||||||||||||||||
| import com.project.rdb.batch.model.repository.BatchExecutionReportRepository; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| @Component | ||||||||||||||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||||||||||||||
| public class BatchStepMetricsListener implements StepExecutionListener { | ||||||||||||||||||||||||||||||||||||||
| private final BatchExecutionReportRepository reportRepository; | ||||||||||||||||||||||||||||||||||||||
| private final ObjectMapper objectMapper; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||
| public ExitStatus afterStep(StepExecution stepExecution) { | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| JobExecution jobExecution = stepExecution.getJobExecution(); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| LocalDateTime start = | ||||||||||||||||||||||||||||||||||||||
| Objects.requireNonNull(stepExecution.getStartTime()) | ||||||||||||||||||||||||||||||||||||||
| .atZone(ZoneId.of("Asia/Seoul")) | ||||||||||||||||||||||||||||||||||||||
| .toLocalDateTime(); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| LocalDateTime end = | ||||||||||||||||||||||||||||||||||||||
| Objects.requireNonNull(stepExecution.getEndTime()) | ||||||||||||||||||||||||||||||||||||||
| .atZone(ZoneId.of("Asia/Seoul")) | ||||||||||||||||||||||||||||||||||||||
| .toLocalDateTime(); | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+33
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| long durationMs = Duration.between(start, end).toMillis(); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| long readCount = stepExecution.getReadCount(); | ||||||||||||||||||||||||||||||||||||||
| BigDecimal tps = | ||||||||||||||||||||||||||||||||||||||
| durationMs > 0 | ||||||||||||||||||||||||||||||||||||||
| ? BigDecimal.valueOf(readCount) | ||||||||||||||||||||||||||||||||||||||
| .multiply(BigDecimal.valueOf(1000)) | ||||||||||||||||||||||||||||||||||||||
| .divide(BigDecimal.valueOf(durationMs), 2, RoundingMode.HALF_UP) | ||||||||||||||||||||||||||||||||||||||
| : BigDecimal.ZERO; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| String paramsJson; | ||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||
| paramsJson = | ||||||||||||||||||||||||||||||||||||||
| objectMapper.writeValueAsString( | ||||||||||||||||||||||||||||||||||||||
| jobExecution.getJobParameters().getParameters()); | ||||||||||||||||||||||||||||||||||||||
| } catch (Exception e) { | ||||||||||||||||||||||||||||||||||||||
| paramsJson = "{}"; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| reportRepository.save( | ||||||||||||||||||||||||||||||||||||||
| BatchExecutionReport.builder() | ||||||||||||||||||||||||||||||||||||||
| .jobName(jobExecution.getJobInstance().getJobName()) | ||||||||||||||||||||||||||||||||||||||
| .stepName(stepExecution.getStepName()) | ||||||||||||||||||||||||||||||||||||||
| .status(stepExecution.getStatus().toString()) | ||||||||||||||||||||||||||||||||||||||
| .startedAt(start) | ||||||||||||||||||||||||||||||||||||||
| .endedAt(end) | ||||||||||||||||||||||||||||||||||||||
| .durationMs(durationMs) | ||||||||||||||||||||||||||||||||||||||
| .readCount(readCount) | ||||||||||||||||||||||||||||||||||||||
| .writeCount(stepExecution.getWriteCount()) | ||||||||||||||||||||||||||||||||||||||
| .filterCount(stepExecution.getFilterCount()) | ||||||||||||||||||||||||||||||||||||||
| .skipCount(stepExecution.getSkipCount()) | ||||||||||||||||||||||||||||||||||||||
| .commitCount(stepExecution.getCommitCount()) | ||||||||||||||||||||||||||||||||||||||
| .rollbackCount(stepExecution.getRollbackCount()) | ||||||||||||||||||||||||||||||||||||||
| .tps(tps) | ||||||||||||||||||||||||||||||||||||||
| .jobParameters(paramsJson) | ||||||||||||||||||||||||||||||||||||||
| .createdAt(LocalDateTime.now()) | ||||||||||||||||||||||||||||||||||||||
| .build()); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return stepExecution.getExitStatus(); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.project.rdb.batch.model.dto; | ||
|
|
||
| import java.util.concurrent.CompletableFuture; | ||
|
|
||
| import org.springframework.kafka.support.SendResult; | ||
|
|
||
| public record NotificationSendTask( | ||
| UsageNotificationEvent event, CompletableFuture<SendResult<String, String>> future) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| package com.project.rdb.batch.model.dto; | ||
|
|
||
| public record UsageDailyAggregation(Long subId, String usageDate, long deltaBytes) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package com.project.rdb.batch.model.dto; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| public record UsageDailyKey(Long subId, String usageDate) { | ||
| @Override | ||
| public boolean equals(Object oj) { | ||
| if (this == oj) { | ||
| return true; | ||
| } | ||
| if (!(oj instanceof UsageDailyKey that)) { | ||
| return false; | ||
| } | ||
| return Objects.equals(subId, that.subId) && Objects.equals(usageDate, that.usageDate); | ||
| } | ||
| } | ||
|
Comment on lines
+6
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package com.project.rdb.batch.model.dto; | ||
|
|
||
| import java.time.LocalDateTime; | ||
|
|
||
| public record UsageLogRow(Long subId, Long usedBytes, LocalDateTime eventTime) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| package com.project.rdb.batch.model.dto; | ||
|
|
||
| public record UsageMonthlyAggregation(Long subId, String period, long deltaBytes) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package com.project.rdb.batch.model.dto; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| public record UsageMonthlyKey(Long subId, String period) { | ||
|
|
||
| @Override | ||
| public boolean equals(Object oj) { | ||
| if (this == oj) { | ||
| return true; | ||
| } | ||
| if (!(oj instanceof UsageMonthlyKey that)) { | ||
| return false; | ||
| } | ||
| return Objects.equals(subId, that.subId) && Objects.equals(period, that.period); | ||
| } | ||
| } | ||
|
Comment on lines
+7
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.project.rdb.batch.model.dto; | ||
|
|
||
| public record UsageNotificationCandidate( | ||
| Long subId, | ||
| String period, | ||
| String unit, | ||
| int threshold, | ||
| int percent, | ||
| long totalUsedMb, | ||
| long allotmentMb) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package com.project.rdb.batch.model.dto; | ||
|
|
||
| import java.util.UUID; | ||
|
|
||
| public record UsageNotificationEvent( | ||
| UUID eventId, | ||
| Long id, | ||
| Long subId, | ||
| String period, | ||
| String unit, | ||
| int threshold, | ||
| int percent, | ||
| long totalUsedMb, | ||
| long allotmentMb) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.project.rdb.batch.model.dto; | ||
|
|
||
| public record UsageNotificationOutboxRow( | ||
| Long id, | ||
| Long subId, | ||
| String period, | ||
| String unit, | ||
| int threshold, | ||
| int percent, | ||
| long totalUsedMb, | ||
| long allotmentMb) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| package com.project.rdb.batch.model.dto; | ||
|
|
||
| public record UsageNotificationSource( | ||
| Long subId, String period, String unit, long totalUsedBytes, long allotmentAmount) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FixedBackOff설정에 대한 주석이 실제 동작과 다릅니다.new FixedBackOff(1000L, 2)는 초기 시도를 포함하여 총 3번의 시도를 의미합니다. 하지만 주석에는총 5번 시도(초기+9)라고 되어 있어 혼란을 줄 수 있습니다. 주석을총 3번 시도(초기+2)와 같이 실제 동작에 맞게 수정하는 것이 좋겠습니다.