daadaadaah / review-study-app

0 stars 0 forks source link

임시 저장 #8

Open daadaadaah opened 2 months ago

daadaadaah commented 2 months ago

    // JSON 문자열에서 제네릭 객체를 추출하는 함수
    // 참고 : https://hianna.tistory.com/631
    public static <T> T convertJsonStringToObject(String jsonString, Class<T> clazz) throws Exception {
        log.info("JSON 문자열에서 객체를 추출합니다. jsonString={}, class={}", jsonString, clazz.getClass());

        try {
            return objectMapper.readValue(jsonString, clazz);
        } catch (Exception exception) {
            log.error("JSON 문자열에서 객체 추출을 실패했습니다. exception={}, jsonString={}, class={} ", exception, jsonString, clazz.getClass());
            throw exception;
        }
    }

    // JSON 문자열에서 지정된 타입의 객체 컬렉션을 추출하는 함수
    public static <T, C extends Collection<T>> C extractCollectionFromJsonString(String jsonString, Class<T> clazz, Supplier<C> collectionFactory) throws Exception {
        C resultCollection = collectionFactory.get();

        log.info("JSON 문자열에서 객체를 추출합니다. jsonString={}, collection={}", jsonString, resultCollection.getClass());

        try {
            JsonNode jsonNodes = objectMapper.readTree(jsonString);

            for (JsonNode jsonNode : jsonNodes) {
                T object = objectMapper.treeToValue(jsonNode, clazz);
                resultCollection.add(object);
            }

            return resultCollection;
        } catch (Exception exception) {
            log.error("JSON 문자열에서 컬렉션 추출을 실패했습니다. exception={}, jsonString={}, collection={}", exception.getMessage(), jsonString, resultCollection.getClass());

            throw exception;
        }
    }
daadaadaah commented 2 months ago
public MyHttpResponse getWithRetry(MyHttpRequest request) throws Exception {
        ResponseEntity<String> response = retryTemplate.execute(context -> {
            log.info("{} 번째 재시도 중입니다...", context.getRetryCount());

            try {
                return restTemplate.exchange(
                    request.url(),
                    HttpMethod.GET,
                    new HttpEntity<>(request.body(), request.headers()),
                    String.class
                );
            } catch (HttpClientErrorException httpClientErrorException) {
                HttpStatusCode httpStatusCode = httpClientErrorException.getStatusCode();

                log.warn("statusCode={}, headers={}", httpStatusCode, httpClientErrorException.getResponseHeaders());

//                if(httpStatusCode == HttpStatus.NOT_FOUND) {
//                    throw new RetryableException(httpClientErrorException, context.getRetryCount());
//                }

                throw httpClientErrorException;

            } catch (HttpServerErrorException httpServerErrorException) {
                HttpStatusCode httpStatusCode = httpServerErrorException.getStatusCode();

                log.warn("statusCode={}, headers={}", httpStatusCode, httpServerErrorException.getResponseHeaders());

                log.error("서버 에러 예외가 발생했습니다. exception={} ", httpServerErrorException.getMessage());

                throw new RetryableException(httpServerErrorException, context.getRetryCount());
            } catch (Exception e) {
                log.error("예상하지 못한 예외가 발생했습니다. exception={} ", e.getMessage());
                throw e;
            }
        }, context -> {
            // TODO : RecoveryCallback

            context.getLastThrowable();
            //
            throw new RuntimeException("재시도 깥지 했는데 안됨");
        });

        return new MyHttpResponse(response.getStatusCodeValue(), response.getHeaders(), response.getBody());
    }
daadaadaah commented 2 months ago

@Slf4j
@Component
@Deprecated
@Aspect // TODO : 일단 보류
public class TaskExecutionTimeLogAspect {

    private final LogGoogleSheetsRepository logGoogleSheetsRepository;
    private final LogHelper logHelper;

    @Autowired
    public TaskExecutionTimeLogAspect(
        LogGoogleSheetsRepository logGoogleSheetsRepository,
        LogHelper logHelper
    ) {
        this.logGoogleSheetsRepository = logGoogleSheetsRepository;
        this.logHelper = logHelper;
    }

    @Around("execution(* com.example.review_study_app.github.GithubFacade.*(..))")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();

        Object proceed = joinPoint.proceed();

        GithubApiResult githubApiResult = (GithubApiResult) proceed;

        long current = System.currentTimeMillis();

        long executionTime = current - start;

        log.info("{} executed in {} ms", joinPoint.getSignature(), executionTime);

        TaskExecutionTimeLog taskExecutionTimeLog = new TaskExecutionTimeLog(
            current,
            logHelper.getEnvironment(),
            joinPoint.getSignature().getName(),
            githubApiResult.githubApiSuccessResults().size(),
            githubApiResult.githubApiFailureResults().size(),
            executionTime,
            logHelper.getCreatedAt(current)
        );

        try {
            logGoogleSheetsRepository.save(taskExecutionTimeLog);
        } catch (Exception exception) { // TODO : 예외로직

        }

        return proceed;
    }

//    @Around("execution(* com.example.review_study_app.github.GithubFacade.*(..))")
//    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
//        long start = System.currentTimeMillis();
//        Object proceed = null;
//        boolean success = true;
//        GithubApiResult githubApiResult = null;
//
//        try {
//            proceed = joinPoint.proceed();
//            githubApiResult = (GithubApiResult) proceed;
//        } catch (Throwable throwable) {
//            success = false;
//            log.error("Exception occurred in method {}: {}", joinPoint.getSignature(), throwable.getMessage(), throwable);
//            throw throwable; // Rethrow the exception to ensure the method's exception is propagated
//        } finally {
//            long current = System.currentTimeMillis();
//            long executionTime = current - start;
//
//            log.info("{} executed in {} ms", joinPoint.getSignature(), executionTime);
//
//            TaskExecutionTimeLog taskExecutionTimeLog = new TaskExecutionTimeLog(
//                current,
//                logHelper.getEnvironment(),
//                joinPoint.getSignature().getName(),
//                githubApiResult != null ? githubApiResult.githubApiSuccessResults().size() : 0,
//                githubApiResult != null ? githubApiResult.githubApiFailureResults().size() : 0,
//                executionTime,
//                logHelper.getCreatedAt(current),
//                success
//            );
//
//            try {
//                logGoogleSheetsRepository.save(taskExecutionTimeLog);
//            } catch (Exception exception) {
//                log.error("Failed to save execution time log: {}", exception.getMessage(), exception);
//            }
//        }
//
//        return proceed;
//    }
}
daadaadaah commented 2 months ago
  1. 디자인 패턴(예 : 퍼사드 패턴, 데코레이터 패턴)을 활용하여 복잡한 클래스의 책임을 단순화
  2. @Async를 활용하여 최대 성능 30배(60초 -> 2초) 향상
  3. 로깅 시스템 구축
    • Google Sheets API를 활용하여 GitHub API 통신 및 작업별 수행 시간 로그 관리 -> 작업별 수행 시간 로그를 Google Sheets에 자동으로 기록하여 실시간 모니터링 및 분석 가능.
    • 인터셉터로 관심사 분리?+한번만 소비 가능 문제 해결
    • AOP : retry 로직 -> AOP를 활용하여 재시도 메커니즘의 투명성과 유지보수성 향상.
daadaadaah commented 2 months ago
    private String[] createFlattenedArray(long id, String environment, String[] logData, String createdAt) {
        // Convert id to String
        String idString = Long.toString(id);

        // Calculate the total length of the resulting array
        int totalLength = 1 + 1 + logData.length + 1; // 1 for id, 1 for environment, logData.length for logData, 1 for createdAt

        // Create the resulting array
        String[] result = new String[totalLength];

        // Fill the array with the values
        int index = 0;
        result[index++] = idString; // Add id
        result[index++] = environment; // Add environment
        System.arraycopy(logData, 0, result, index, logData.length); // Add flattened logData
        index += logData.length;
        result[index] = createdAt; // Add createdAt

        return result;
    }
daadaadaah commented 2 months ago
    String credentialsJson = "{"
        + "  \"type\": \"service_account\","
        + "  \"project_id\": \"your_project_id\","
        + "  \"private_key_id\": \"1ec7b3c57791029dd09add5efd4d6879a95b44df\","
        + "  \"private_key\": \"-----BEGIN PRIVATE KEY-----\\n"
        + "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5OIJxnO1Wd78L\\n"
        + "zQV9efwK7otz/rj4+Qwtn+uiVojz6heUhxMxiZ+US3u/lrnDUR7uBCcVRDCJ+09p\\n"
        + "oib8hKmwXfQlBENu3JdfkWXIOgZ70tjqxQWfe+hPcnIM4a7/E93IFCN37fbQlSMq\\n"
        + "4PKLzsV4QZ8NUC0RCXhOjyj/Sct/8/Arp4pH4Rxaq6H+QM5MktIW8YKAojJ9XS3r\\n"
        + "KD4oMWgnR3jPikfQtGIObATq3cN1C+alXLrTHjoU0A2fcI4f0M2SOtdurSp2E/NJ\\n"
        + "VGHBTTiokGHZQ9+ouho8DPSp/lCLp5fi1G0z0fVgagai1mPgkILHSOKyx556x4QD\\n"
        + "ZpWH9fT5AgMBAAECggEAKXrrU7BWQrgck/L9WMV52aTknDyehjuYK5uV9Mw2bZGu\\n"
        + "aDf752svztE8zIJf5csEBz/s1MlpqW0bssd6vbCkI/hWlfendmt2hxOT3MyJ6S8m\\n"
        + "HyWyha4FL82slw/v1fZIA+fmrZQgY0QTFSY9i2vqM21Wxm9/OEKLq+RJxSpspaHE\\n"
        + "VByOTNkasoZhz2+9l4NrxSWltpPs74CeWolWQLpi/w+F/VpgFOBWZ/1k/8oOgGCx\\n"
        + "4D+0Ucu++hYB2UQYtVVy/2Ryo3rJnpHsOaD6Iihx6K8kOJ59zEV6SgpGVP0F8nOZ\\n"
        + "IwaXxD/As4SXP5eQBCkLaPkXr/4hSZO75+WUzdC0BQKBgQD61R0/tPRbXZAgP38G\\n"
        + "WvjA+fH4j6xE96r/nqeSOY7+WUpoi95mrjMoTkMwLaHfFhRcWGklRIyG4tDYDYgd\\n"
        + "s6DlV3RhQT9FOJH2KFYjWm//8YNh2ULKqp1P65vhkd1aOgvmoxzPxb7UfUyGOo8i\\n"
        + "8CtudmCHdDvahXjapTfIe31cvwKBgQC9CVw4GHSnh4uVvLTkBXfkfG9YnFHW7VQH\\n"
        + "skiZMrNNXa+r3m4gUt1nKh/rD+RPNvN0TpBCEc20jwjAVfW7CHeN3TCUbHDS9Fzo\\n"
        + "/atGbELbPV9qk42kUd2I7n5b7bP3djFIyzUq/nzP3Phw3PPwV9x6pkLjPXe8ozlA\\n"
        + "Y6+ie5HERwKBgQCXGYBIG0LEMyWaN4XWl0CYRzj7Sdk1pphs6e76CBBaqgFH31H3\\n"
        + "OuL4WcThpeuIDq3vPxb/6z5YFxRFwkkH02iOH1OtLnflxAExbvUM0PL9FEjXzeAN\\n"
        + "ZB/lwAGkLZFRQ/xdUE8P3ohpSp2pkmcdXd5b6ZWWo29W4OZ/l911uOY40wKBgFqh\\n"
        + "qzol14Aex3iiAeQ1DvdYBZZpU/+Ex73s50uz+C1GlpwDR69tq0Lz+lubwe2Mvgps\\n"
        + "RFO473P7A8obLHZgp9k3TDxNBYbOq+D1BfH8o80zTpTta4J10Y3+Mkzm2Vryqsxo\\n"
        + "yPP1EWgjXGXYOYhox4dyQS1r4gVqCF/rq2BueEOvAoGBAIVCOGT0EhOY+2z2ZJEl\\n"
        + "HzxHWybnXBFV6TfRgQW2PhPvzmkIi4PMe7s1BK6EjO7YuqYpWI4ZBxgW10WKC6AL\\n"
        + "ABPAwsgfctmdhCSW1iCm0iWUWwHwlKMb0uW2Y4osxDPS5CVf4FPh4IpR/rrvM1LV\\n"
        + "YlnjU+2zwyPSlJJswxSWJqy+\\n-----END PRIVATE KEY-----\\n\","
        + "  \"client_email\": \"google-spread-sheet@review-study-app-429913.iam.gserviceaccount.com\","
        + "  \"client_id\": \"115751476084120918586\","
        + "  \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\","
        + "  \"token_uri\": \"https://oauth2.googleapis.com/token\","
        + "  \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\","
        + "  \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/google-spread-sheet@review-study-app-429913.iam.gserviceaccount.com\","
        + "  \"universe_domain\": \"googleapis.com\""
        + "}";