Skip to content
Open
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
8 changes: 7 additions & 1 deletion apps/commerce-api/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
dependencies {
implementation(project(":apps:commerce-core"))

// add-ons
implementation(project(":modules:jpa"))
implementation(project(":modules:redis"))
Expand All @@ -19,6 +19,9 @@ dependencies {
exclude(group = "org.yaml", module = "snakeyaml")
}

// Spring Batch
implementation("org.springframework.boot:spring-boot-starter-batch")

// Resilience4j
implementation("io.github.resilience4j:resilience4j-spring-boot3:${project.properties["resilience4jVersion"]}")
implementation("org.springframework.boot:spring-boot-starter-aop")
Expand All @@ -29,6 +32,9 @@ dependencies {
annotationProcessor("jakarta.persistence:jakarta.persistence-api")
annotationProcessor("jakarta.annotation:jakarta.annotation-api")

// Spring Batch Test (ํ…Œ์ŠคํŠธ์šฉ)
testImplementation("org.springframework.batch:spring-batch-test")

// test-fixtures
testImplementation(testFixtures(project(":modules:jpa")))
testImplementation(testFixtures(project(":modules:redis")))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.loopers.application.ranking;

import lombok.Getter;
import org.springframework.batch.core.JobExecution;

/**
* ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰ ๊ฒฐ๊ณผ ์ •๋ณด
*/
@Getter
public class RankingAggregationInfo {

private final Long jobExecutionId;
private final String jobName;
private final String status;
private final String exitStatus;
private final String period; // "weekly" or "monthly"
private final String message;

private RankingAggregationInfo(
Long jobExecutionId,
String jobName,
String status,
String exitStatus,
String period,
String message
) {
this.jobExecutionId = jobExecutionId;
this.jobName = jobName;
this.status = status;
this.exitStatus = exitStatus;
this.period = period;
this.message = message;
}

public static RankingAggregationInfo from(JobExecution jobExecution, String period) {
return new RankingAggregationInfo(
jobExecution.getId(),
jobExecution.getJobInstance().getJobName(),
jobExecution.getStatus().name(),
jobExecution.getExitStatus() != null ? jobExecution.getExitStatus().getExitCode() : null,
period,
jobExecution.getExitStatus() != null ? jobExecution.getExitStatus().getExitDescription() : null
);
}

public static RankingAggregationInfo combined(
RankingAggregationInfo weekly,
RankingAggregationInfo monthly
) {
boolean bothSuccess = "COMPLETED".equals(weekly.status) && "COMPLETED".equals(monthly.status);
String combinedStatus = bothSuccess ? "COMPLETED" : "FAILED";
String combinedMessage = String.format(
"Weekly: %s, Monthly: %s",
weekly.status,
monthly.status
);

return new RankingAggregationInfo(
null, // combined์—๋Š” jobExecutionId ์—†์Œ
"weeklyAndMonthlyRankingJob",
combinedStatus,
bothSuccess ? "COMPLETED" : "FAILED",
"both",
combinedMessage
);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.loopers.application.ranking;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.ZonedDateTime;

/**
* ์ฃผ๊ฐ„, ์›”๊ฐ„ ๋žญํ‚น ์Šค์ผ€์ค„๋Ÿฌ
* <p>
* ๋งค์ผ ์ž์ •์— ์ผ๊ฐ„ ์ง‘๊ณ„ ์™„๋ฃŒ ํ›„ ์ฃผ๊ฐ„, ์›”๊ฐ„ ๋žญํ‚น์„ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.
* ์Šคํ”„๋ง ๋ฐฐ์น˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ tb_product_metrics_daily์˜ ์ผ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ง‘๊ณ„ํ•˜๊ณ ,
* ์ฃผ๊ฐ„ ๋ฐ ์›”๊ฐ„ ๋žญํ‚น์„ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
* ์ด ์ž‘์—…์€ Chunk ๋‹จ์œ„๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
* spring batch read process write ํŒจํ„ด์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class RankingAggregationScheduler {

private final RankingAggregationService rankingAggregationService;

/**
* ๋งค์ผ ์ž์ •์— ์‹คํ–‰ (์ผ๊ฐ„ ์ง‘๊ณ„ ์™„๋ฃŒ ํ›„)
* ์ฃผ๊ฐ„, ์›”๊ฐ„ ๋žญํ‚น ๊ฐฑ์‹ 
*/
@Scheduled(cron = "0 0 0 * * *") // ๋งค์ผ ์ž์ •
public void aggregateWeeklyAndMonthlyRankings() {
try {
log.info("์Šค์ผ€์ค„๋Ÿฌ: ์ฃผ๊ฐ„ ๋ฐ ์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰ ์‹œ์ž‘");

// ์–ด์ œ ๋‚ ์งœ ๊ธฐ์ค€์œผ๋กœ ์ง‘๊ณ„ (์˜ค๋Š˜ ์ž์ •์— ์‹คํ–‰๋˜๋ฏ€๋กœ ์–ด์ œ ๋ฐ์ดํ„ฐ๊นŒ์ง€ ์ง‘๊ณ„)
ZonedDateTime targetDate = ZonedDateTime.now().minusDays(1);
Comment on lines +30 to +36
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

โš ๏ธ Potential issue | ๐ŸŸ  Major

๐Ÿงฉ Analysis chain

๐Ÿ Script executed:

# First, check the file size and read the full RankingAggregationScheduler.java
wc -l apps/commerce-api/src/main/java/com/loopers/application/ranking/RankingAggregationScheduler.java

Repository: Loopers-dev-lab/loopers-spring-java-template

Length of output: 187


๐Ÿ Script executed:

# Read the full file to understand context
cat -n apps/commerce-api/src/main/java/com/loopers/application/ranking/RankingAggregationScheduler.java

Repository: Loopers-dev-lab/loopers-spring-java-template

Length of output: 1742


๐Ÿ Script executed:

# Search for daily aggregation related schedulers or methods
rg -i "daily.*aggregat|aggregat.*daily" --type java

Repository: Loopers-dev-lab/loopers-spring-java-template

Length of output: 7869


๐Ÿ Script executed:

# Search for ZoneId usage in the codebase to understand timezone patterns
rg "ZoneId" --type java -A 2 -B 2

Repository: Loopers-dev-lab/loopers-spring-java-template

Length of output: 867


๐Ÿ Script executed:

# Check if there's any timezone configuration in application properties
find . -name "application*.properties" -o -name "application*.yml" | head -5 | xargs grep -l "timezone\|zone" 2>/dev/null || echo "No timezone config found"

Repository: Loopers-dev-lab/loopers-spring-java-template

Length of output: 112


๐Ÿ Script executed:

# Search for batch job configurations
find . -name "*Batch*.java" -o -name "*Job*.java" | head -20

Repository: Loopers-dev-lab/loopers-spring-java-template

Length of output: 767


๐Ÿ Script executed:

# Search for daily aggregation or metrics daily job
rg "daily|Daily" apps/commerce-api/src/main/java/com/loopers/application/ranking/batch/ --type java -l

Repository: Loopers-dev-lab/loopers-spring-java-template

Length of output: 484


๐Ÿ Script executed:

# Check RankingAggregationService to understand the flow
find . -name "RankingAggregationService.java" -type f

Repository: Loopers-dev-lab/loopers-spring-java-template

Length of output: 184


๐Ÿ Script executed:

# Read the RankingAggregationService
cat -n apps/commerce-api/src/main/java/com/loopers/application/ranking/RankingAggregationService.java

Repository: Loopers-dev-lab/loopers-spring-java-template

Length of output: 7699


๐Ÿ Script executed:

# Check the RankingAggregationJobConfig to understand batch execution
cat -n apps/commerce-api/src/main/java/com/loopers/application/ranking/batch/RankingAggregationJobConfig.java

Repository: Loopers-dev-lab/loopers-spring-java-template

Length of output: 1220


๐Ÿ Script executed:

# Search for any daily metrics aggregation batch jobs
rg -i "metrics.*daily|daily.*metrics" apps/commerce-api/src/main/java --type java -l

Repository: Loopers-dev-lab/loopers-spring-java-template

Length of output: 581


๐Ÿ Script executed:

# Check if there are multiple scheduled tasks
rg "@Scheduled" --type java -B 2 -A 1

Repository: Loopers-dev-lab/loopers-spring-java-template

Length of output: 2152


์‹œ์Šคํ…œ ํƒ€์ž„์กด์— ๋Œ€ํ•œ ๋ช…์‹œ์  ์ง€์ • ํ•„์š”

ZonedDateTime.now()๋Š” ์‹œ์Šคํ…œ ๊ธฐ๋ณธ ํƒ€์ž„์กด์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ๋ฐฐํฌ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ™์€ ์„œ๋น„์Šค์˜ ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ๋“ค(๋ผ์ธ 54-60)์—์„œ๋Š” ์ด๋ฏธ targetDate.getZone()์œผ๋กœ ๋ช…์‹œ์  ํƒ€์ž„์กด์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ, ์ผ๊ด€์„ฑ ์œ ์ง€๋ฅผ ์œ„ํ•ด ์—ฌ๊ธฐ์„œ๋„ ๊ฐ™์€ ๋ฐฉ์‹์„ ์ ์šฉํ•˜์„ธ์š”:

-        ZonedDateTime targetDate = ZonedDateTime.now().minusDays(1);
+        ZonedDateTime targetDate = ZonedDateTime.now(ZoneId.of("Asia/Seoul")).minusDays(1);

๋˜ํ•œ ํด๋ž˜์Šค ์ฃผ์„์—์„œ "์ผ๊ฐ„ ์ง‘๊ณ„ ์™„๋ฃŒ ํ›„" ์‹คํ–‰๋œ๋‹ค๊ณ  ๋ช…์‹œ๋˜์–ด ์žˆ์œผ๋‚˜, ์‹ค์ œ ์ผ๊ฐ„ ์ง‘๊ณ„ ๋ฐฐ์น˜๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜๋„ํ•œ ์ผ๊ฐ„ ์ง‘๊ณ„ ๋ฐฐ์น˜์™€์˜ ์‹คํ–‰ ์ˆœ์„œ ๋ณด์žฅ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ํ™•์ธํ•˜๊ณ  ํ•„์š”์‹œ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿค– Prompt for AI Agents
In
apps/commerce-api/src/main/java/com/loopers/application/ranking/RankingAggregationScheduler.java
around lines 30 to 36, replace the use of ZonedDateTime.now() with an explicit
ZoneId to match the other methods (lines 54-60): obtain the same ZoneId used
elsewhere (either by reusing the existing variable/utility or by
injecting/configuring a ZoneId) and call ZonedDateTime.now(zone).minusDays(1) so
the targetDate uses the explicit timezone; additionally, verify and if necessary
enforce the intended execution ordering with the daily aggregation job (e.g.,
wire in the configured scheduler/bean order or use a coordination mechanism like
@DependsOn or explicit task chaining) so the weekly/monthly run occurs after
daily aggregation.


rankingAggregationService.executeWeeklyAndMonthlyRanking(targetDate);

log.info("์Šค์ผ€์ค„๋Ÿฌ: ์ฃผ๊ฐ„ ๋ฐ ์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰ ์™„๋ฃŒ");

} catch (Exception e) {
log.error("์Šค์ผ€์ค„๋Ÿฌ: ์ฃผ๊ฐ„ ๋ฐ ์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰ ์‹คํŒจ", e);
// ์Šค์ผ€์ค„๋Ÿฌ๋Š” ์˜ˆ์™ธ๋ฅผ ๋˜์ง€์ง€ ์•Š๊ณ  ๋กœ๊ทธ๋งŒ ๋‚จ๊น€ (๋‹ค์Œ ์‹คํ–‰์— ์˜ํ–ฅ ์ฃผ์ง€ ์•Š์Œ)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package com.loopers.application.ranking;

import com.loopers.support.error.CoreException;
import com.loopers.support.error.ErrorType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.time.DayOfWeek;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAdjusters;

/**
* ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์„œ๋น„์Šค
* <p>
* ์ฃผ๊ฐ„/์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
*/
@Slf4j
@Component
public class RankingAggregationService {

private final JobLauncher jobLauncher;
private final Job rankingJob;

public RankingAggregationService(
JobLauncher jobLauncher,
@Qualifier("rankingJob") Job rankingJob
) {
this.jobLauncher = jobLauncher;
this.rankingJob = rankingJob;
}

/**
* ์ฃผ๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰
*
* @param targetDate ์ง‘๊ณ„ ๋Œ€์ƒ ๋‚ ์งœ (์ด ๋‚ ์งœ๊ฐ€ ์†ํ•œ ์ฃผ๊ฐ„์„ ์ง‘๊ณ„)
* @return JobExecution ์‹คํ–‰ ๊ฒฐ๊ณผ
* @note Spring Batch๋Š” ์ž์ฒด ํŠธ๋žœ์žญ์…˜์„ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ @Transactional์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
*/
public RankingAggregationInfo executeWeeklyRanking(ZonedDateTime targetDate) {
if (targetDate == null) {
throw new CoreException(ErrorType.BAD_REQUEST, "์ง‘๊ณ„ ๋Œ€์ƒ ๋‚ ์งœ๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.");
}

log.info("์ฃผ๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰ ์‹œ์ž‘: targetDate={}", targetDate);

try {
// ์ฃผ๊ฐ„ ์‹œ์ž‘์ผ/์ข…๋ฃŒ์ผ ๊ณ„์‚ฐ
ZonedDateTime weekStart = targetDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
.toLocalDate()
.atStartOfDay(targetDate.getZone());
ZonedDateTime weekEnd = targetDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY))
.toLocalDate()
.atTime(23, 59, 59)
.atZone(targetDate.getZone());
ZonedDateTime rankingDate = weekEnd;

// Job ํŒŒ๋ผ๋ฏธํ„ฐ ์ƒ์„ฑ
JobParameters jobParameters = new JobParametersBuilder()
.addString("periodType", "weekly")
.addString("rankingDate", rankingDate.toString())
.addString("startDate", weekStart.toLocalDate().toString())
.addString("endDate", weekEnd.toLocalDate().toString())
.addLong("timestamp", System.currentTimeMillis())
.toJobParameters();

// ๋ฐฐ์น˜ ์‹คํ–‰
JobExecution jobExecution = jobLauncher.run(rankingJob, jobParameters);

log.info("์ฃผ๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰ ์™„๋ฃŒ: jobExecutionId={}, status={}, exitStatus={}",
jobExecution.getId(),
jobExecution.getStatus(),
jobExecution.getExitStatus());

return RankingAggregationInfo.from(jobExecution, "weekly");

} catch (Exception e) {
log.error("์ฃผ๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰ ์‹คํŒจ: targetDate={}", targetDate, e);
throw new CoreException(ErrorType.INTERNAL_ERROR,
"์ฃผ๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค: " + e.getMessage());
}
}

/**
* ์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰
*
* @param targetDate ์ง‘๊ณ„ ๋Œ€์ƒ ๋‚ ์งœ (์ด ๋‚ ์งœ๊ฐ€ ์†ํ•œ ์›”๊ฐ„์„ ์ง‘๊ณ„)
* @return JobExecution ์‹คํ–‰ ๊ฒฐ๊ณผ
* @note Spring Batch๋Š” ์ž์ฒด ํŠธ๋žœ์žญ์…˜์„ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ @Transactional์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
*/
public RankingAggregationInfo executeMonthlyRanking(ZonedDateTime targetDate) {
if (targetDate == null) {
throw new CoreException(ErrorType.BAD_REQUEST, "์ง‘๊ณ„ ๋Œ€์ƒ ๋‚ ์งœ๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.");
}

log.info("์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰ ์‹œ์ž‘: targetDate={}", targetDate);

try {
// ์›”๊ฐ„ ์‹œ์ž‘์ผ/์ข…๋ฃŒ์ผ ๊ณ„์‚ฐ
ZonedDateTime monthStart = targetDate.with(TemporalAdjusters.firstDayOfMonth())
.toLocalDate()
.atStartOfDay(targetDate.getZone());
ZonedDateTime monthEnd = targetDate.with(TemporalAdjusters.lastDayOfMonth())
.toLocalDate()
.atTime(23, 59, 59)
.atZone(targetDate.getZone());
ZonedDateTime rankingDate = monthEnd;

// Job ํŒŒ๋ผ๋ฏธํ„ฐ ์ƒ์„ฑ
// monthly๋Š” Reader์—์„œ ์ตœ๊ทผ 30์ผ๋กœ ์ž๋™ ๊ณ„์‚ฐํ•˜๋ฏ€๋กœ startDate/endDate ์ƒ๋žต
JobParameters jobParameters = new JobParametersBuilder()
.addString("periodType", "monthly")
.addString("rankingDate", rankingDate.toString())
// startDate, endDate๋Š” Reader์—์„œ ์ž๋™ ๊ณ„์‚ฐ (์ตœ๊ทผ 30์ผ)
.addLong("timestamp", System.currentTimeMillis())
.toJobParameters();

// ๋ฐฐ์น˜ ์‹คํ–‰
JobExecution jobExecution = jobLauncher.run(rankingJob, jobParameters);

log.info("์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰ ์™„๋ฃŒ: jobExecutionId={}, status={}, exitStatus={}",
jobExecution.getId(),
jobExecution.getStatus(),
jobExecution.getExitStatus());

return RankingAggregationInfo.from(jobExecution, "monthly");

} catch (Exception e) {
log.error("์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰ ์‹คํŒจ: targetDate={}", targetDate, e);
throw new CoreException(ErrorType.INTERNAL_ERROR,
"์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค: " + e.getMessage());
}
}

/**
* ์ฃผ๊ฐ„ ๋ฐ ์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰
*
* @param targetDate ์ง‘๊ณ„ ๋Œ€์ƒ ๋‚ ์งœ
* @return ๋ฐฐ์น˜ ์‹คํ–‰ ๊ฒฐ๊ณผ
* @note Spring Batch๋Š” ์ž์ฒด ํŠธ๋žœ์žญ์…˜์„ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ @Transactional์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
*/
public RankingAggregationInfo executeWeeklyAndMonthlyRanking(ZonedDateTime targetDate) {
if (targetDate == null) {
throw new CoreException(ErrorType.BAD_REQUEST, "์ง‘๊ณ„ ๋Œ€์ƒ ๋‚ ์งœ๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.");
}

log.info("์ฃผ๊ฐ„ ๋ฐ ์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰ ์‹œ์ž‘: targetDate={}", targetDate);

try {
// ์ฃผ๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„
RankingAggregationInfo weeklyResult = executeWeeklyRanking(targetDate);

// ์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„
RankingAggregationInfo monthlyResult = executeMonthlyRanking(targetDate);

log.info("์ฃผ๊ฐ„ ๋ฐ ์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰ ์™„๋ฃŒ");

return RankingAggregationInfo.combined(weeklyResult, monthlyResult);

} catch (Exception e) {
log.error("์ฃผ๊ฐ„ ๋ฐ ์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰ ์‹คํŒจ: targetDate={}", targetDate, e);
throw new CoreException(ErrorType.INTERNAL_ERROR,
"์ฃผ๊ฐ„ ๋ฐ ์›”๊ฐ„ ๋žญํ‚น ์ง‘๊ณ„ ๋ฐฐ์น˜ ์‹คํ–‰์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค: " + e.getMessage());
}
}
}

Loading