From fe1b9155c236277c8088411e2183093bc3795f45 Mon Sep 17 00:00:00 2001 From: Junha Date: Sun, 30 Mar 2025 19:43:49 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix:=20I/O=20Bound,=20Cpu=20Bound=20Thread?= =?UTF-8?q?=20pool=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../futsalMatch/config/ApplicationConfig.java | 16 +++++++--- .../futsalMatch/config/AsyncConfig.java | 16 ++++++++++ .../service/PlatformRequestService.java | 20 ++++++------ .../service/PlatformRequester.java | 14 ++++++++ .../strategy/parsing/ParsingStrategy.java | 8 +++++ .../strategy/parsing/PlabParsingStrategy.java | 19 +++++++++++ .../parsing/PuzzleParsingStrategy.java | 29 +++++++++++++++++ .../parsing/UrbanParsingStrategy.java | 24 ++++++++++++++ .../strategy/parsing/WithParsingStrategy.java | 29 +++++++++++++++++ .../strategy/request/PlabRequestStrategy.java | 28 ++++++++++++++++ .../request/PuzzleRequestStrategy.java | 24 ++++++++++++++ .../strategy/request/RequestStrategy.java | 1 + .../request/UrbanRequestStrategy.java | 24 ++++++++++++++ .../strategy/request/WithRequestStrategy.java | 32 +++++++++++++++++++ 14 files changed, 271 insertions(+), 13 deletions(-) create mode 100644 src/main/java/futsal/futsalMatch/config/AsyncConfig.java create mode 100644 src/main/java/futsal/futsalMatch/service/strategy/parsing/ParsingStrategy.java create mode 100644 src/main/java/futsal/futsalMatch/service/strategy/parsing/PlabParsingStrategy.java create mode 100644 src/main/java/futsal/futsalMatch/service/strategy/parsing/PuzzleParsingStrategy.java create mode 100644 src/main/java/futsal/futsalMatch/service/strategy/parsing/UrbanParsingStrategy.java create mode 100644 src/main/java/futsal/futsalMatch/service/strategy/parsing/WithParsingStrategy.java diff --git a/src/main/java/futsal/futsalMatch/config/ApplicationConfig.java b/src/main/java/futsal/futsalMatch/config/ApplicationConfig.java index 8a28062..0c2940a 100644 --- a/src/main/java/futsal/futsalMatch/config/ApplicationConfig.java +++ b/src/main/java/futsal/futsalMatch/config/ApplicationConfig.java @@ -5,6 +5,10 @@ import futsal.futsalMatch.config.platform.UrbanConfig; import futsal.futsalMatch.config.platform.WithConfig; import futsal.futsalMatch.service.PlatformRequester; +import futsal.futsalMatch.service.strategy.parsing.PlabParsingStrategy; +import futsal.futsalMatch.service.strategy.parsing.PuzzleParsingStrategy; +import futsal.futsalMatch.service.strategy.parsing.UrbanParsingStrategy; +import futsal.futsalMatch.service.strategy.parsing.WithParsingStrategy; import futsal.futsalMatch.service.strategy.request.PlabRequestStrategy; import futsal.futsalMatch.service.strategy.request.PuzzleRequestStrategy; import futsal.futsalMatch.service.strategy.request.UrbanRequestStrategy; @@ -21,39 +25,43 @@ @RequiredArgsConstructor public class ApplicationConfig { private final PlabRequestStrategy plabRequestStrategy; + private final PlabParsingStrategy plabParsingStrategy; private final PlabTransformStrategy plabTransformStrategy; private final PlabConfig plabConfig; private final PuzzleRequestStrategy puzzleRequestStrategy; + private final PuzzleParsingStrategy puzzleParsingStrategy; private final PuzzleTransformStrategy puzzleTransformStrategy; private final PuzzleConfig puzzleConfig; private final WithRequestStrategy withRequestStrategy; + private final WithParsingStrategy withParsingStrategy; private final WithTransformStrategy withTransformStrategy; private final WithConfig withConfig; private final UrbanRequestStrategy urbanRequestStrategy; + private final UrbanParsingStrategy urbanParsingStrategy; private final UrbanTransformStrategy urbanTransformStrategy; private final UrbanConfig urbanConfig; @Bean public PlatformRequester plabRequester() { - return new PlatformRequester(plabRequestStrategy, plabTransformStrategy, plabConfig); + return new PlatformRequester(plabRequestStrategy, plabParsingStrategy, plabTransformStrategy, plabConfig); } @Bean public PlatformRequester puzzleRequester() { - return new PlatformRequester(puzzleRequestStrategy, puzzleTransformStrategy, puzzleConfig); + return new PlatformRequester(puzzleRequestStrategy, puzzleParsingStrategy, puzzleTransformStrategy, puzzleConfig); } @Bean public PlatformRequester withRequester() { - return new PlatformRequester(withRequestStrategy, withTransformStrategy, withConfig); + return new PlatformRequester(withRequestStrategy, withParsingStrategy, withTransformStrategy, withConfig); } @Bean public PlatformRequester urbanRequester() { - return new PlatformRequester(urbanRequestStrategy, urbanTransformStrategy, urbanConfig); + return new PlatformRequester(urbanRequestStrategy, urbanParsingStrategy, urbanTransformStrategy, urbanConfig); } diff --git a/src/main/java/futsal/futsalMatch/config/AsyncConfig.java b/src/main/java/futsal/futsalMatch/config/AsyncConfig.java new file mode 100644 index 0000000..e14dd25 --- /dev/null +++ b/src/main/java/futsal/futsalMatch/config/AsyncConfig.java @@ -0,0 +1,16 @@ +package futsal.futsalMatch.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Configuration +public class AsyncConfig { + + @Bean + public ExecutorService ioThreadPool() { + return Executors.newFixedThreadPool(50); + } +} diff --git a/src/main/java/futsal/futsalMatch/service/PlatformRequestService.java b/src/main/java/futsal/futsalMatch/service/PlatformRequestService.java index 6b92b61..4b03e5c 100644 --- a/src/main/java/futsal/futsalMatch/service/PlatformRequestService.java +++ b/src/main/java/futsal/futsalMatch/service/PlatformRequestService.java @@ -11,6 +11,7 @@ import java.util.Comparator; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; @Service @Slf4j @@ -18,23 +19,24 @@ public class PlatformRequestService { private final List requesters; + private final ExecutorService ioThreadPool; public List fetchAllData(LocalDate date, Region region) { List result = requesters.stream() - .map(requester -> CompletableFuture.supplyAsync(() -> { - try { - return requester.request(date, region); - } catch (Exception e) { - log.error("Error in {} - {}", requester.getClass().getSimpleName(), e.getMessage()); - return List.of(); - } - })) + .map(requester -> CompletableFuture + .supplyAsync(() -> requester.fetch(date, region), ioThreadPool) + .thenApplyAsync(fetchData -> requester.parse(fetchData, date)) + .thenApply(requester::transform) + .exceptionally(e -> { + log.error("Error in {} - {}", requester.getClass().getSimpleName(), e.getMessage()); + return List.of(); + }) + ) .map(CompletableFuture::join) .flatMap(List::stream) .filter(m -> isValidTime(m.getTime())) .sorted(Comparator.comparing(m -> LocalTime.parse(m.getTime()))) .toList(); - return removeExpiredMatch(date, result); } diff --git a/src/main/java/futsal/futsalMatch/service/PlatformRequester.java b/src/main/java/futsal/futsalMatch/service/PlatformRequester.java index 23807a6..a77c0d1 100644 --- a/src/main/java/futsal/futsalMatch/service/PlatformRequester.java +++ b/src/main/java/futsal/futsalMatch/service/PlatformRequester.java @@ -3,6 +3,7 @@ import futsal.futsalMatch.config.platform.PlatformConfig; import futsal.futsalMatch.domain.MatchInfo; import futsal.futsalMatch.enums.Region; +import futsal.futsalMatch.service.strategy.parsing.ParsingStrategy; import futsal.futsalMatch.service.strategy.request.RequestStrategy; import futsal.futsalMatch.service.strategy.transform.TransformStrategy; import lombok.RequiredArgsConstructor; @@ -13,9 +14,22 @@ @RequiredArgsConstructor public class PlatformRequester { private final RequestStrategy requestStrategy; + private final ParsingStrategy parsingStrategy; private final TransformStrategy transformStrategy; private final PlatformConfig config; + public String fetch(LocalDate date, Region region) { + return requestStrategy.fetch(config, date, region); + } + + public List parse(String fetchData, LocalDate date) { + return parsingStrategy.parse(fetchData, date); + } + + public List transform(List matchList) { + return matchList.stream().map(data -> transformStrategy.transform(config, data)).toList(); + } + public List request(LocalDate date, Region region) { return requestStrategy.request(config, date, region) .stream() diff --git a/src/main/java/futsal/futsalMatch/service/strategy/parsing/ParsingStrategy.java b/src/main/java/futsal/futsalMatch/service/strategy/parsing/ParsingStrategy.java new file mode 100644 index 0000000..ab9854e --- /dev/null +++ b/src/main/java/futsal/futsalMatch/service/strategy/parsing/ParsingStrategy.java @@ -0,0 +1,8 @@ +package futsal.futsalMatch.service.strategy.parsing; + +import java.time.LocalDate; +import java.util.List; + +public interface ParsingStrategy { + List parse(String fetchData, LocalDate date); +} diff --git a/src/main/java/futsal/futsalMatch/service/strategy/parsing/PlabParsingStrategy.java b/src/main/java/futsal/futsalMatch/service/strategy/parsing/PlabParsingStrategy.java new file mode 100644 index 0000000..1d6a4d4 --- /dev/null +++ b/src/main/java/futsal/futsalMatch/service/strategy/parsing/PlabParsingStrategy.java @@ -0,0 +1,19 @@ +package futsal.futsalMatch.service.strategy.parsing; + +import org.json.JSONArray; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.util.List; +import java.util.stream.IntStream; + +@Component +public class PlabParsingStrategy implements ParsingStrategy { + @Override + public List parse(String fetchData, LocalDate date) { + JSONArray jsonArray = new JSONArray(fetchData); + return IntStream.range(0, jsonArray.length()) + .mapToObj(jsonArray::get) + .toList(); + } +} diff --git a/src/main/java/futsal/futsalMatch/service/strategy/parsing/PuzzleParsingStrategy.java b/src/main/java/futsal/futsalMatch/service/strategy/parsing/PuzzleParsingStrategy.java new file mode 100644 index 0000000..d18d494 --- /dev/null +++ b/src/main/java/futsal/futsalMatch/service/strategy/parsing/PuzzleParsingStrategy.java @@ -0,0 +1,29 @@ +package futsal.futsalMatch.service.strategy.parsing; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.util.List; +import java.util.stream.IntStream; + +@Component +public class PuzzleParsingStrategy implements ParsingStrategy { + @Override + public List parse(String fetchData, LocalDate date) { + JSONObject jsonData = new JSONObject(fetchData); + + if(!jsonData.has("list")) { + return List.of(); //매치가 없을 때 + } + + JSONArray jsonArray = jsonData.getJSONArray("list"); + + // Note: JSONArray.toList()는 사용하지 말 것. + // 사용 시 JSONArray의 데이터를 List으로 변환하므로, 이후 JSONObject로 처리할 수 없음. + return IntStream.range(0, jsonArray.length()) + .mapToObj(jsonArray::get) + .toList(); + } +} diff --git a/src/main/java/futsal/futsalMatch/service/strategy/parsing/UrbanParsingStrategy.java b/src/main/java/futsal/futsalMatch/service/strategy/parsing/UrbanParsingStrategy.java new file mode 100644 index 0000000..107114a --- /dev/null +++ b/src/main/java/futsal/futsalMatch/service/strategy/parsing/UrbanParsingStrategy.java @@ -0,0 +1,24 @@ +package futsal.futsalMatch.service.strategy.parsing; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.select.Elements; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.util.List; + +@Component +public class UrbanParsingStrategy implements ParsingStrategy { + @Override + public List parse(String fetchData, LocalDate date) { + Document document = Jsoup.parse(fetchData); + Elements matchElements = document.select("ul.goods_table_item"); + + String dateElement = "" + date + ""; + + return matchElements.stream() + .map(matchElement -> (Object) (matchElement + dateElement)) + .toList(); + } +} diff --git a/src/main/java/futsal/futsalMatch/service/strategy/parsing/WithParsingStrategy.java b/src/main/java/futsal/futsalMatch/service/strategy/parsing/WithParsingStrategy.java new file mode 100644 index 0000000..9479a85 --- /dev/null +++ b/src/main/java/futsal/futsalMatch/service/strategy/parsing/WithParsingStrategy.java @@ -0,0 +1,29 @@ +package futsal.futsalMatch.service.strategy.parsing; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.util.List; +import java.util.stream.IntStream; + +@Component +public class WithParsingStrategy implements ParsingStrategy { + @Override + public List parse(String fetchData, LocalDate date) { + JSONObject jsonData = new JSONObject(fetchData.substring(11)); //starts with "200 OK OK,{JsonData...}" + + if(!jsonData.has("block_list")) { + return List.of(); //매치가 없을 때 + } + + JSONArray jsonArray = jsonData.getJSONArray("block_list"); + + // Note: JSONArray.toList()는 사용하지 말 것. + // 사용 시 JSONArray의 데이터를 List으로 변환하므로, 이후 JSONObject로 처리할 수 없음. + return IntStream.range(0, jsonArray.length()) + .mapToObj(jsonArray::get) + .toList(); + } +} diff --git a/src/main/java/futsal/futsalMatch/service/strategy/request/PlabRequestStrategy.java b/src/main/java/futsal/futsalMatch/service/strategy/request/PlabRequestStrategy.java index c123d1b..1eff93c 100644 --- a/src/main/java/futsal/futsalMatch/service/strategy/request/PlabRequestStrategy.java +++ b/src/main/java/futsal/futsalMatch/service/strategy/request/PlabRequestStrategy.java @@ -55,4 +55,32 @@ public List request(PlatformConfig config, LocalDate date, Region region return List.of(); } } + + @Override + public String fetch(PlatformConfig config, LocalDate date, Region region) { + String requestUrl = UriComponentsBuilder.fromHttpUrl(config.getRequestBaseURL()) + .queryParam("sch", date) + .queryParam("region", "1") //TODO region 값 변환 + .queryParam("page_size", "700") + .queryParam("ordering", "schedule") + .build().toString(); + + try { + ResponseEntity response = restTemplate.exchange( + requestUrl, + HttpMethod.GET, + new HttpEntity<>(new HttpHeaders()), + String.class + ); + + if(response.getStatusCode() != HttpStatus.OK){ + throw new UnexpectedResponseStatusException("Unexpected response status: " + response.getStatusCode()); + } + + return response.getBody(); + } catch (Exception e){ + log.error("플랩풋볼 요청 실패 : {} - {}", e.getClass().getSimpleName(), e.getMessage()); + return ""; + } + } } diff --git a/src/main/java/futsal/futsalMatch/service/strategy/request/PuzzleRequestStrategy.java b/src/main/java/futsal/futsalMatch/service/strategy/request/PuzzleRequestStrategy.java index fce488c..4984433 100644 --- a/src/main/java/futsal/futsalMatch/service/strategy/request/PuzzleRequestStrategy.java +++ b/src/main/java/futsal/futsalMatch/service/strategy/request/PuzzleRequestStrategy.java @@ -59,6 +59,30 @@ public List request(PlatformConfig config, LocalDate date, Region region } } + @Override + public String fetch(PlatformConfig config, LocalDate date, Region region) { + HttpHeaders requestHeaders = buildHttpHeaders(); + JSONObject requestBody = buildRequestBody(config, date, region, requestHeaders); + + try{ + ResponseEntity response = restTemplate.exchange( + config.getRequestBaseURL(), + HttpMethod.POST, + new HttpEntity<>(requestBody.toString(), requestHeaders), + String.class + ); + + if(response.getStatusCode() != HttpStatus.OK){ + throw new UnexpectedResponseStatusException("Unexpected response status: " + response.getStatusCode()); + } + + return response.getBody(); + } catch (Exception e){ + log.error("퍼즐플레이 요청 실패 : {} - {}", e.getClass().getSimpleName(), e.getMessage()); + return ""; + } + } + private HttpHeaders buildHttpHeaders() { HttpHeaders headers = new HttpHeaders(); headers.set("Accept", "*/*"); diff --git a/src/main/java/futsal/futsalMatch/service/strategy/request/RequestStrategy.java b/src/main/java/futsal/futsalMatch/service/strategy/request/RequestStrategy.java index ce483e1..5835f04 100644 --- a/src/main/java/futsal/futsalMatch/service/strategy/request/RequestStrategy.java +++ b/src/main/java/futsal/futsalMatch/service/strategy/request/RequestStrategy.java @@ -8,4 +8,5 @@ public interface RequestStrategy { List request(PlatformConfig config, LocalDate date, Region region); + String fetch(PlatformConfig config, LocalDate date, Region region); } diff --git a/src/main/java/futsal/futsalMatch/service/strategy/request/UrbanRequestStrategy.java b/src/main/java/futsal/futsalMatch/service/strategy/request/UrbanRequestStrategy.java index a4dc287..9e80194 100644 --- a/src/main/java/futsal/futsalMatch/service/strategy/request/UrbanRequestStrategy.java +++ b/src/main/java/futsal/futsalMatch/service/strategy/request/UrbanRequestStrategy.java @@ -53,6 +53,30 @@ public List request(PlatformConfig config, LocalDate date, Region region } } + @Override + public String fetch(PlatformConfig config, LocalDate date, Region region) { + HttpHeaders requestHeaders = buildHttpHeaders(); + String requestBody = "mode=get_goods_list&date=" + date.toString() + "&area=11"; + + try{ + ResponseEntity response = restTemplate.exchange( + config.getRequestBaseURL(), + HttpMethod.POST, + new HttpEntity<>(requestBody, requestHeaders), + String.class + ); + + if(response.getStatusCode() != HttpStatus.OK){ + throw new UnexpectedResponseStatusException("Unexpected response status: " + response.getStatusCode()); + } + + return response.getBody(); + } catch (Exception e){ + log.error("어반풋볼 요청 실패 : {} - {}", e.getClass().getSimpleName(), e.getMessage()); + return ""; + } + } + private HttpHeaders buildHttpHeaders() { HttpHeaders headers = new HttpHeaders(); headers.set("Accept", "*/*"); diff --git a/src/main/java/futsal/futsalMatch/service/strategy/request/WithRequestStrategy.java b/src/main/java/futsal/futsalMatch/service/strategy/request/WithRequestStrategy.java index 52b92ee..c9e3187 100644 --- a/src/main/java/futsal/futsalMatch/service/strategy/request/WithRequestStrategy.java +++ b/src/main/java/futsal/futsalMatch/service/strategy/request/WithRequestStrategy.java @@ -66,4 +66,36 @@ public List request(PlatformConfig config, LocalDate date, Region region return List.of(); } } + + @Override + public String fetch(PlatformConfig config, LocalDate date, Region region) { + if(region == Region.GYEONGGI) { + return ""; + } + + String requestUrl = UriComponentsBuilder.fromHttpUrl(config.getRequestBaseURL()) + .queryParam("cmd", "search-info") + .queryParam("day", date.toString()) + .queryParam("area_code", "0") + .queryParam("member_code", "all") + .build().toString(); + + try{ + ResponseEntity response = restTemplate.exchange( + requestUrl, + HttpMethod.GET, + new HttpEntity<>(new HttpHeaders()), + String.class + ); + + if(response.getStatusCode() != HttpStatus.OK){ + throw new UnexpectedResponseStatusException("Unexpected response status: " + response.getStatusCode()); + } + + return response.toString(); + } catch (Exception e){ + log.error("위드풋살 요청 실패 : {} - {}", e.getClass().getSimpleName(), e.getMessage()); + return ""; + } + } } From 3e6acc0b9b2863439a1007a2e76ba607beb8bde9 Mon Sep 17 00:00:00 2001 From: Junha Date: Sun, 4 May 2025 10:49:15 +0900 Subject: [PATCH 2/4] remove: logging component --- .../futsal/futsalMatch/config/WebConfig.java | 20 --------- .../controller/ResetController.java | 19 -------- .../interceptor/LoggingInterceptor.java | 44 ------------------- 3 files changed, 83 deletions(-) delete mode 100644 src/main/java/futsal/futsalMatch/config/WebConfig.java delete mode 100644 src/main/java/futsal/futsalMatch/controller/ResetController.java delete mode 100644 src/main/java/futsal/futsalMatch/interceptor/LoggingInterceptor.java diff --git a/src/main/java/futsal/futsalMatch/config/WebConfig.java b/src/main/java/futsal/futsalMatch/config/WebConfig.java deleted file mode 100644 index eb109f0..0000000 --- a/src/main/java/futsal/futsalMatch/config/WebConfig.java +++ /dev/null @@ -1,20 +0,0 @@ -package futsal.futsalMatch.config; - -import futsal.futsalMatch.interceptor.LoggingInterceptor; -import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -@RequiredArgsConstructor -public class WebConfig implements WebMvcConfigurer { - - private final LoggingInterceptor loggingInterceptor; - - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(loggingInterceptor) - .excludePathPatterns("/reset"); - } -} diff --git a/src/main/java/futsal/futsalMatch/controller/ResetController.java b/src/main/java/futsal/futsalMatch/controller/ResetController.java deleted file mode 100644 index 5920c20..0000000 --- a/src/main/java/futsal/futsalMatch/controller/ResetController.java +++ /dev/null @@ -1,19 +0,0 @@ -package futsal.futsalMatch.controller; - -import futsal.futsalMatch.interceptor.LoggingInterceptor; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -public class ResetController { - - private final LoggingInterceptor loggingInterceptor; - - @GetMapping("/reset") - public String reset() { - loggingInterceptor.reset(); - return "reset"; - } -} diff --git a/src/main/java/futsal/futsalMatch/interceptor/LoggingInterceptor.java b/src/main/java/futsal/futsalMatch/interceptor/LoggingInterceptor.java deleted file mode 100644 index 3ac90ff..0000000 --- a/src/main/java/futsal/futsalMatch/interceptor/LoggingInterceptor.java +++ /dev/null @@ -1,44 +0,0 @@ -package futsal.futsalMatch.interceptor; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; -import org.springframework.web.servlet.HandlerInterceptor; - -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -@Component -@Slf4j -public class LoggingInterceptor implements HandlerInterceptor { - - private AtomicInteger count = new AtomicInteger(0); - private AtomicLong sumOfTime = new AtomicLong(0); - - private synchronized long getAverage() { - return sumOfTime.get() / count.get(); - } - - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - request.setAttribute("startTime", System.currentTimeMillis()); - return true; - } - - @Override - public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { - Long startTime = (Long) request.getAttribute("startTime"); - long endTime = System.currentTimeMillis(); - count.getAndIncrement(); - sumOfTime.getAndAdd(endTime - startTime); - String fullUrl = request.getRequestURI() + "?" + request.getQueryString(); - log.info("[{}] {} 처리 시간: {}ms", request.getMethod(), fullUrl, (endTime - startTime)); - log.info("평균 처리시간 : {}ms", getAverage()); - } - - public void reset() { - count.set(0); - sumOfTime.set(0); - } -} From 1219d372be0617cbe83c8a58d7e832dae4f90b2e Mon Sep 17 00:00:00 2001 From: Junha Date: Sun, 4 May 2025 10:52:59 +0900 Subject: [PATCH 3/4] fix: stream.parallel() to work properly --- src/main/java/futsal/futsalMatch/config/AsyncConfig.java | 2 +- .../java/futsal/futsalMatch/service/PlatformRequestService.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/futsal/futsalMatch/config/AsyncConfig.java b/src/main/java/futsal/futsalMatch/config/AsyncConfig.java index e14dd25..1caca46 100644 --- a/src/main/java/futsal/futsalMatch/config/AsyncConfig.java +++ b/src/main/java/futsal/futsalMatch/config/AsyncConfig.java @@ -11,6 +11,6 @@ public class AsyncConfig { @Bean public ExecutorService ioThreadPool() { - return Executors.newFixedThreadPool(50); + return Executors.newFixedThreadPool(100); } } diff --git a/src/main/java/futsal/futsalMatch/service/PlatformRequestService.java b/src/main/java/futsal/futsalMatch/service/PlatformRequestService.java index 4b03e5c..7aa9b14 100644 --- a/src/main/java/futsal/futsalMatch/service/PlatformRequestService.java +++ b/src/main/java/futsal/futsalMatch/service/PlatformRequestService.java @@ -32,6 +32,7 @@ public List fetchAllData(LocalDate date, Region region) { return List.of(); }) ) + .parallel() .map(CompletableFuture::join) .flatMap(List::stream) .filter(m -> isValidTime(m.getTime())) From 6040c01bb112e91b21f2b4558952ba50964219e7 Mon Sep 17 00:00:00 2001 From: Junha Date: Sun, 4 May 2025 10:55:19 +0900 Subject: [PATCH 4/4] fix: handle updated PLAB data structure --- .../service/strategy/parsing/PlabParsingStrategy.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/futsal/futsalMatch/service/strategy/parsing/PlabParsingStrategy.java b/src/main/java/futsal/futsalMatch/service/strategy/parsing/PlabParsingStrategy.java index 1d6a4d4..9180dc4 100644 --- a/src/main/java/futsal/futsalMatch/service/strategy/parsing/PlabParsingStrategy.java +++ b/src/main/java/futsal/futsalMatch/service/strategy/parsing/PlabParsingStrategy.java @@ -1,6 +1,7 @@ package futsal.futsalMatch.service.strategy.parsing; import org.json.JSONArray; +import org.json.JSONObject; import org.springframework.stereotype.Component; import java.time.LocalDate; @@ -11,7 +12,13 @@ public class PlabParsingStrategy implements ParsingStrategy { @Override public List parse(String fetchData, LocalDate date) { - JSONArray jsonArray = new JSONArray(fetchData); + JSONObject jsonData = new JSONObject(fetchData); + + if(!jsonData.has("results")) { + return List.of(); //매치가 없을 때 + } + + JSONArray jsonArray = jsonData.getJSONArray("results"); return IntStream.range(0, jsonArray.length()) .mapToObj(jsonArray::get) .toList();