hyeonga_code

Project_15_CompletableFuture 적용하기 본문

Project_HYEONGARL

Project_15_CompletableFuture 적용하기

hyeonga 2024. 6. 25. 06:59
반응형

 

Url을 저장하는 다이어리가 주제인 프로젝트를 작업 중이다.

 

CompletableFuture를 사용하여 비동기 작업을 처리하는 것은 주로 서비스 계층에서 데이터베이스 접근 및 캐시 작업과 관련된 부분에서 사용할 수 있다.

 

데이터베이스의 저장, 조회, 업데이트, 삭제 작업을 비동기로 처리하여 응답 시간을 단축하여 서비스의 성능을 향상시키고 대기 시간을 줄일 수 있다.

 

현재 프로젝트에서 캐시를 사용하여 카테고리 관련 기능을 구현했는데 카테고리 수정 시 캐시를 업데이트하고 데이터베이스에 수정 사항을 저장하는 작업을 비동기로 처리할 수 있다.

 

 

CategoryService

> 이전 코드

더보기
    @CachePut(value = "category", key = "#userId")
    public Category updateCategory(Category category, Long userId) {
        Logger.servicelogging("save");
        Category existCategory = categoryRepository.findByUserId(userId)
                .orElseThrow(CategoryNotFoundException::new);
        existCategory.setCategoryTree(category.getCategoryTree() != null ?
                category.getCategoryTree() : existCategory.getCategoryTree());
        return categoryRepository.save(existCategory);
    }

 

> 수정 코드

    @CachePut(value = "category", key = "#userId")
    public CompletableFuture<Category> updateCategory(Category category, Long userId) {
        Logger.servicelogging("save");

        log.info("비동기 처리 전");
        CompletableFuture<Category> result = CompletableFuture.supplyAsync(() -> {
            log.info("비동기 처리 시작");
            Category existCategory = categoryRepository.findByUserId(userId)
                    .orElseThrow(CategoryNotFoundException::new);
            log.info("비동기 처리 중  : categoryRepository.findByUserId()");
            existCategory.setCategoryTree(category.getCategoryTree() != null ?
                    category.getCategoryTree() : existCategory.getCategoryTree());

            log.info("비동기 처리 완료  : existCategory.setCategoryTree()");
            return categoryRepository.save(existCategory);
        });
        log.info("비동기 처리 후");
        return result;
    }

 

 

 

CategoryController

> 이전 코드

더보기
    @PutMapping
    public CategoryResponseDto updateCategory(@RequestBody CategoryRequestDto categoryRequest) {
        Logger.logging("updateCategory");
        return CategoryResponseDto
            .fromEntity(categoryService.updateCategory(
                categoryRequest.toEntity(), tokenService.getUserId()));
    }

 

> 수정 코드

    @PutMapping
    public CompletableFuture<CategoryResponseDto> updateCategory(
        @RequestBody CategoryRequestDto categoryRequest) {
        Logger.logging("updateCategory");

        return categoryService.updateCategory(
                categoryRequest.toEntity(), tokenService.getUserId()
            ).thenApply(CategoryResponseDto::fromEntity);
    }

 

 

CategoryServiceTest

> 수정 코드

    @Test
    @DisplayName("update_success")  // CompletableFuture 적용
    void updateCategory_success() throws ExecutionException, InterruptedException {
        when(categoryRepository.findByUserId(anyLong())).thenReturn(Optional.ofNullable(category));
        when(categoryRepository.save(any(Category.class))).thenReturn(category);

        CompletableFuture<Category> result 
            = categoryService.updateCategory(categoryRequest.toEntity(), 1L);
        Category update = result.get();

        assertNotNull(update);
        assertEquals(categoryTree, update.getCategoryTree());

        verify(categoryRepository, times(1)).findByUserId(anyLong());
        verify(categoryRepository, times(1)).save(any(Category.class));
    }

 

 

> 실행

// Test worker 				>> Main 스레드
[Test worker] INFO -- ----- save -----
[Test worker] INFO -- 비동기 처리 전

 // 비동기 작업 이후 코드가 먼저 출력된다.
[Test worker] INFO -- 비동기 처리 후

 // ForkJoinPool.commonPool-worker-1 	>> Main 스레드가 아닌 다른 스레드에서 실행
[ForkJoinPool.commonPool-worker-1] INFO -- 비동기 처리 시작
[ForkJoinPool.commonPool-worker-1] INFO -- 비동기 처리 중  : categoryRepository.findByUserId()
[ForkJoinPool.commonPool-worker-1] INFOe -- 비동기 처리 완료  : existCategory.setCategoryTree()

 

더보기

1. Test worker > 기존에 사용되고 있는 메인 스레드이다.

 

2. ForkJoinPool.commonPool-worker-1 > CompletableFuture에서 사용하는 스레드로  ForkJoinPool의 스레드이다.

 

3. 메인 스레드는 비동기 작업이 완료되기 전에 다음 코드를 실행한다.

    즉, 데이터베이스 쿼리가 실행되기 전, 즉 비동기 작업이 시작되기 전에 "비동기 처리 후" 로그가 출력된다.

 

4. 비동기 작업을 다른 스레드에서 실행한다.(메인스레드가 ForkJoinPool의 스레드에 요청)

 

로그 확인하기

비동기 처리 전 : 비동기 작업이 시작되기 전에 출력된다.

비동기 처리 후 : 비동기 작업이 시작되기 전에 출력된다.

비동기 처리 시작 : 비동기 작업이 새로운 스레드에서 시작되었음을 나타낸다.

비동기 처리 중 :데이터베이스 조회가 실행되고 있음을 나타낸다.

비동기 처리 완료 : 비동기 작업이 완료되었음을 나타낸다.

 

 

반응형