아빠는 개발자

[Aqqle] YahooDataService 의 execute 본문

Aqqle/EXTRACT

[Aqqle] YahooDataService 의 execute

father6019 2025. 2. 1. 21:08
728x90
반응형

 

Ya후의 stock 서비를 크롤링해서 데이터를 훔처오는 service 인데 대충 만들다보니 리팩토링좀 해야할듯..

 

기존소스의 개선점

  • 예외 처리 로직 강화
  • 병렬 처리 최적화 (CompletableFuture.allOf)
  • 하드코딩된 경로 제거
  • 가독성과 유지보수성 향상
package com.doo.aqqle.service;

import com.doo.aqqle.annotation.Timer;
import com.doo.aqqle.repository.StockDataRepository;
import com.doo.aqqle.repository.StockRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@Slf4j
@Service("YahooDataService")
public class YahooDataService extends ExtractService implements AqqleExtract {

    private final YahooDataTaskService yahooDataTaskService;
    private List<CompletableFuture<Integer>> completableFutures = new ArrayList<>();

    public YahooDataService(StockRepository stockRepository, StockDataRepository stockDataRepository, YahooDataTaskService yahooDataTaskService) {
        super(stockRepository, stockDataRepository);
        this.yahooDataTaskService = yahooDataTaskService;
    }

    @Override
    @Timer
    public void execute() {

        String type = "yahoo";
        String extractPath = "/data/" + type + "/static/";

        File file = new File(extractPath);

        if (file.exists() && file.isDirectory()) {
            try {
                FileUtils.cleanDirectory(file);
            } catch (IOException e) {
                e.getStackTrace();
            }

        }

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
        String directory = extractPath + LocalDateTime.now().format(dateTimeFormatter).toString();

        System.out.println(directory);
        IndexFileService.createDirectory(directory);

        long count = stockDataRepository.count();
        int chunk = 500;
        double endPage = Math.ceil(count / chunk);

        for (int i = 0; i < endPage + 1; i++) {
            CompletableFuture<Integer> completableFuture = yahooDataTaskService.task(i, chunk, directory);
            completableFutures.add(completableFuture);
        }

        for (CompletableFuture<Integer> future : completableFutures) {
            try {
                future.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }


    }
}

 

1. 예외 처리 개선

문제점:

현재 IOException, InterruptedException, ExecutionException에 대해 e.printStackTrace()로만 예외 처리를 하고 있습니다. 이는 충분히 의미 있는 로그 정보를 제공하지 않습니다.

개선 방법:

  • 명확한 로그 메시지를 추가하고 예외 정보를 함께 출력합니다.
  • 예외 발생 시 적절한 조치를 취할 수 있도록 코드를 작성합니다.

 

 

2. CompletableFuture 병렬 처리 최적화

문제점:

모든 CompletableFuture의 결과를 순차적으로 기다리며 future.get()을 호출합니다. 이는 비효율적입니다.

개선 방법:

  • CompletableFuture.allOf()로 모든 작업이 완료되기를 비동기적으로 기다립니다.

 

3. 디렉터리 경로 관리

문제점:

경로 /data/yahoo/static/가 하드코딩되어 있습니다.
이는 운영 환경에서 관리가 어렵고 유연성이 부족합니다.

개선 방법:

  • 환경 변수나 설정 파일 (application.yml)을 통해 경로를 관리합니다.

 

4. 코드 가독성 개선

  • 불필요한 toString() 호출 제거
  • List<CompletableFuture<Integer>> completableFutures는 메서드 내부에서 선언하여 코드 간섭을 줄입니다.

 

 

수정된 코드

package com.doo.aqqle.service;

import com.doo.aqqle.annotation.Timer;
import com.doo.aqqle.repository.StockDataRepository;
import com.doo.aqqle.repository.StockRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@Slf4j
@Service("YahooDataService")
public class YahooDataService extends ExtractService implements AqqleExtract {

    @Value("${app.extract-path}")
    private String extractPath;


    private final YahooDataTaskService yahooDataTaskService;
    private List<CompletableFuture<Integer>> completableFutures = new ArrayList<>();


    public YahooDataService(StockRepository stockRepository, StockDataRepository stockDataRepository, YahooDataTaskService yahooDataTaskService) {
        super(stockRepository, stockDataRepository);
        this.yahooDataTaskService = yahooDataTaskService;
    }

    @Override
    @Timer
    public void execute() {

        String type = "yahoo";
        File file = new File(extractPath);

        if (file.exists() && file.isDirectory()) {
            try {
                FileUtils.cleanDirectory(file);
            } catch (IOException e) {
                log.error("Failed to clean directory: {}", extractPath, e);
            }

        }
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
        String directory = extractPath + LocalDateTime.now().format(dateTimeFormatter).toString();

        log.info("directory path : {}", directory);
        IndexFileService.createDirectory(directory);

        long count = stockDataRepository.count();
        int chunk = 500;
        double endPage = Math.ceil(count / chunk);

        for (int i = 0; i < endPage + 1; i++) {
            CompletableFuture<Integer> completableFuture = yahooDataTaskService.task(i, chunk, directory);
            completableFutures.add(completableFuture);
        }
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                completableFutures.toArray(new CompletableFuture[0])
        );
        try {
            allFutures.get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("Thread interrupted during task execution", e);
        } catch (ExecutionException e) {
            log.error("Task execution failed", e);
        }
    }
}

728x90
반응형

'Aqqle > EXTRACT' 카테고리의 다른 글

[Aqqle] 데이터 추출  (0) 2024.02.03