Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: 쪽지 조회시 로깅을 위한 기능 비동기 처리 #584

Open
wants to merge 7 commits into
base: dev_backend
Choose a base branch
from
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
2 changes: 2 additions & 0 deletions backend/src/main/java/com/now/naaga/NaagaApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableAsync
@EnableJpaAuditing
@SpringBootApplication
public class NaagaApplication {
Expand Down
25 changes: 25 additions & 0 deletions backend/src/main/java/com/now/naaga/common/config/AsyncConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.now.naaga.common.config;

import com.now.naaga.letter.application.letterlog.AsyncExceptionHandler;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@Configuration
public class AsyncConfig implements AsyncConfigurer {

@Override
@Bean(name = "asyncExecutor")
public Executor getAsyncExecutor() {
return new ThreadPoolTaskExecutor();
}

@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncExceptionHandler();
}
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
package com.now.naaga.letter.application;

import com.now.naaga.game.application.GameService;
import com.now.naaga.game.application.dto.FindGameInProgressCommand;
import com.now.naaga.game.domain.Game;
import com.now.naaga.letter.application.dto.CreateLetterCommand;
import com.now.naaga.letter.application.letterlog.LetterLogService;
import com.now.naaga.letter.domain.Letter;
import com.now.naaga.letter.domain.letterlog.ReadLetterLog;
import com.now.naaga.letter.domain.letterlog.WriteLetterLog;
import com.now.naaga.letter.exception.LetterException;
import com.now.naaga.letter.presentation.dto.FindLetterLogByGameCommand;
import com.now.naaga.letter.presentation.dto.FindNearByLetterCommand;
import com.now.naaga.letter.presentation.dto.LetterReadCommand;
import com.now.naaga.letter.repository.LetterRepository;
import com.now.naaga.letter.repository.letterlog.ReadLetterLogRepository;
import com.now.naaga.letter.repository.letterlog.WriteLetterLogRepository;
import com.now.naaga.player.application.PlayerService;
import com.now.naaga.player.domain.Player;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

import static com.now.naaga.letter.exception.LetterExceptionType.NO_EXIST;

Expand All @@ -32,88 +24,40 @@ public class LetterService {

private final LetterRepository letterRepository;

private final ReadLetterLogRepository readLetterLogRepository;

private final WriteLetterLogRepository writeLetterLogRepository;

private final PlayerService playerService;

private final GameService gameService;
private final LetterLogService letterLogService;

public LetterService(final LetterRepository letterRepository,
final ReadLetterLogRepository readLetterLogRepository,
final WriteLetterLogRepository writeLetterLogRepository,
final PlayerService playerService,
final GameService gameService) {
final LetterLogService letterLogService) {
this.letterRepository = letterRepository;
this.readLetterLogRepository = readLetterLogRepository;
this.writeLetterLogRepository = writeLetterLogRepository;
this.playerService = playerService;
this.gameService = gameService;
this.letterLogService = letterLogService;
}

public Letter writeLetter(final CreateLetterCommand createLetterCommand) {
final Player player = playerService.findPlayerById(createLetterCommand.playerId());
final Letter letter = new Letter(player, createLetterCommand.position(), createLetterCommand.message());
letterRepository.save(letter);

logWriteLetter(letter);
letterLogService.logWriteLetter(letter);
return letter;
}

private void logWriteLetter(final Letter letter) {
final Game gameInProgress = getGameInProgress(letter.getRegisteredPlayer().getId());
final WriteLetterLog writeLetterLog = new WriteLetterLog(gameInProgress, letter);
writeLetterLogRepository.save(writeLetterLog);
}

@Transactional(readOnly = true)
public Letter findLetter(final LetterReadCommand letterReadCommand) {
final Player player = playerService.findPlayerById(letterReadCommand.playerId());
final Letter foundLetter = letterRepository.findById(letterReadCommand.letterId())
.orElseThrow(() -> new LetterException(NO_EXIST));

logReadLetter(player, foundLetter);
letterLogService.logReadLetter(player, foundLetter);
return foundLetter;
}

private void logReadLetter(final Player player,
final Letter letter) {
final Game gameInProgress = getGameInProgress(player.getId());
boolean isAlreadyReadLetter = isAlreadyReadLetter(gameInProgress, letter);
if(!isAlreadyReadLetter) {
final ReadLetterLog readLetterLog = new ReadLetterLog(gameInProgress, letter);
readLetterLogRepository.save(readLetterLog);
}
}
private boolean isAlreadyReadLetter(final Game game,
final Letter letter) {
Optional<ReadLetterLog> readLetterInGame = readLetterLogRepository
.findByGameIdAndLetterId(game.getId(), letter.getId());
return readLetterInGame.isPresent();
}

@Transactional(readOnly = true)
public List<Letter> findNearByLetters(final FindNearByLetterCommand findNearByLetterCommand) {
return letterRepository.findLetterByPositionAndDistance(findNearByLetterCommand.position(), LETTER_RADIUS);
}

@Transactional(readOnly = true)
public List<Letter> findLetterLogInGame(final FindLetterLogByGameCommand findLetterLogByGameCommand) {
if (findLetterLogByGameCommand.letterLogType().isWrite()) {
final List<WriteLetterLog> writeLetterLogs = writeLetterLogRepository.findByGameId(findLetterLogByGameCommand.gameId());
return writeLetterLogs.stream()
.map(WriteLetterLog::getLetter)
.toList();
}
final List<ReadLetterLog> readLetterLogs = readLetterLogRepository.findByGameId(findLetterLogByGameCommand.gameId());
return readLetterLogs.stream()
.map(ReadLetterLog::getLetter)
.toList();
}

private Game getGameInProgress(final Long playerId) {
final FindGameInProgressCommand findGameByStatusCommand = new FindGameInProgressCommand(playerId);
return gameService.findGameInProgress(findGameByStatusCommand);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.now.naaga.letter.application.letterlog;


import com.now.naaga.common.exception.BaseException;
import com.now.naaga.common.exception.ExceptionResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

private final Logger log = LoggerFactory.getLogger(this.getClass().getSimpleName());

@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
final String errorMessage = ((BaseException) throwable).exceptionType().errorMessage();
final int errorCode = ((BaseException) throwable).exceptionType().errorCode();
final ExceptionResponse exceptionResponse = new ExceptionResponse(errorCode, errorMessage);

log.info("error = {}", exceptionResponse);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.now.naaga.letter.application.letterlog;

import com.now.naaga.game.application.GameService;
import com.now.naaga.game.application.dto.FindGameInProgressCommand;
import com.now.naaga.game.domain.Game;
import com.now.naaga.letter.domain.Letter;
import com.now.naaga.letter.domain.letterlog.ReadLetterLog;
import com.now.naaga.letter.domain.letterlog.WriteLetterLog;
import com.now.naaga.letter.presentation.dto.FindLetterLogByGameCommand;
import com.now.naaga.letter.repository.letterlog.ReadLetterLogRepository;
import com.now.naaga.letter.repository.letterlog.WriteLetterLogRepository;
import com.now.naaga.player.domain.Player;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

@Transactional
@Service
public class LetterLogService {

private final ReadLetterLogRepository readLetterLogRepository;

private final WriteLetterLogRepository writeLetterLogRepository;

private final GameService gameService;

public LetterLogService(final ReadLetterLogRepository readLetterLogRepository,
final WriteLetterLogRepository writeLetterLogRepository,
final GameService gameService) {
this.readLetterLogRepository = readLetterLogRepository;
this.writeLetterLogRepository = writeLetterLogRepository;
this.gameService = gameService;
}

public void logWriteLetter(final Letter letter) {
final Game gameInProgress = getGameInProgress(letter.getRegisteredPlayer().getId());
final WriteLetterLog writeLetterLog = new WriteLetterLog(gameInProgress, letter);
writeLetterLogRepository.save(writeLetterLog);
}

//@Async
public void logReadLetter(final Player player,
final Letter letter) {
final FindGameInProgressCommand findGameByStatusCommand = new FindGameInProgressCommand(player.getId());
final Game gameInProgress = gameService.findGameInProgress(findGameByStatusCommand);
if (!isAlreadyReadLetter(gameInProgress.getId(), letter.getId())) {
final ReadLetterLog readLetterLog = new ReadLetterLog(gameInProgress, letter);
readLetterLogRepository.save(readLetterLog);
}
}

private boolean isAlreadyReadLetter(final Long gameId,
final Long letterId) {
final Optional<ReadLetterLog> readLetterInGame = readLetterLogRepository
.findByGameIdAndLetterId(gameId, letterId);
return readLetterInGame.isPresent();
}

private Game getGameInProgress(final Long playerId) {
final FindGameInProgressCommand findGameByStatusCommand = new FindGameInProgressCommand(playerId);
final Game gameInProgress = gameService.findGameInProgress(findGameByStatusCommand);
return gameInProgress;
}

@Transactional(readOnly = true)
public List<Letter> findLetterLogInGame(final FindLetterLogByGameCommand findLetterLogByGameCommand) {
if (findLetterLogByGameCommand.letterLogType().isWrite()) {
final List<WriteLetterLog> writeLetterLogs = writeLetterLogRepository.findByGameId(findLetterLogByGameCommand.gameId());
return writeLetterLogs.stream()
.map(WriteLetterLog::getLetter)
.toList();
}
final List<ReadLetterLog> readLetterLogs = readLetterLogRepository.findByGameId(findLetterLogByGameCommand.gameId());
return readLetterLogs.stream()
.map(ReadLetterLog::getLetter)
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.now.naaga.auth.presentation.annotation.Auth;
import com.now.naaga.letter.application.LetterService;
import com.now.naaga.letter.application.dto.CreateLetterCommand;
import com.now.naaga.letter.application.letterlog.LetterLogService;
import com.now.naaga.letter.domain.Letter;
import com.now.naaga.letter.domain.letterlog.LetterLogType;
import com.now.naaga.letter.presentation.dto.*;
Expand All @@ -21,8 +22,12 @@ public class LetterController {

private final LetterService letterService;

public LetterController(final LetterService letterService) {
private final LetterLogService letterLogService;

public LetterController(final LetterService letterService,
final LetterLogService letterLogService) {
this.letterService = letterService;
this.letterLogService = letterLogService;
}

@PostMapping("/letters")
Expand Down Expand Up @@ -64,7 +69,7 @@ public ResponseEntity<List<LetterResponse>> findLetterInGame(@Auth final PlayerR
@RequestParam final Long gameId,
@RequestParam final LetterLogType logType) {
final FindLetterLogByGameCommand findLetterLogByGameCommand = FindLetterLogByGameCommand.of(playerRequest, gameId, logType);
final List<Letter> letters = letterService.findLetterLogInGame(findLetterLogByGameCommand);
final List<Letter> letters = letterLogService.findLetterLogInGame(findLetterLogByGameCommand);

final List<LetterResponse> writeLetterResponses = letters.stream()
.map(LetterResponse::from)
Expand Down
3 changes: 3 additions & 0 deletions backend/src/test/java/com/now/naaga/common/AbstractTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.now.naaga.common.builder.TemporaryPlaceBuilder;
import com.now.naaga.common.builder.WriteLetterLogBuilder;
import com.now.naaga.common.infrastructure.AwsS3FileManager;
import com.now.naaga.config.AsyncTestConfig;
import com.now.naaga.game.repository.GameRepository;
import com.now.naaga.game.repository.HintRepository;
import com.now.naaga.gameresult.repository.GameResultRepository;
Expand All @@ -31,11 +32,13 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.jdbc.Sql;

@DisplayNameGeneration(ReplaceUnderscores.class)
@Sql("/truncate.sql")
@ActiveProfiles("test")
@ContextConfiguration(classes = AsyncTestConfig.class)
public abstract class AbstractTest {

/*------------------------------------------------------------------*/
Expand Down
28 changes: 28 additions & 0 deletions backend/src/test/java/com/now/naaga/config/AsyncTestConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.now.naaga.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.core.task.SyncTaskExecutor;

@TestConfiguration
public class AsyncTestConfig {

@Bean
public AsyncExecutorPostProcessor asyncExecutorPostProcessor() {
return new AsyncExecutorPostProcessor();
}

static class AsyncExecutorPostProcessor implements BeanPostProcessor {

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("asyncExecutor")) {
return new SyncTaskExecutor();
}
return bean;
}
}
}
Loading
Loading