diff --git a/src/main/java/com/thirdparty/ticketing/domain/common/GlobalExceptionHandler.java b/src/main/java/com/thirdparty/ticketing/domain/common/GlobalExceptionHandler.java index 6fb06e85..abe97d73 100644 --- a/src/main/java/com/thirdparty/ticketing/domain/common/GlobalExceptionHandler.java +++ b/src/main/java/com/thirdparty/ticketing/domain/common/GlobalExceptionHandler.java @@ -2,6 +2,7 @@ import java.util.List; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -13,6 +14,13 @@ @RestControllerAdvice public class GlobalExceptionHandler { + @ExceptionHandler(Exception.class) + public ResponseEntity> handleAllExceptions(Exception e) { + log.error("예측하지 못한 예외 발생. 메시지={}", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ErrorResponse.of(ErrorCode.INTERNAL_SERVER_ERROR)); + } + @ExceptionHandler(TicketingException.class) public ResponseEntity> handleTicketingException(TicketingException e) { ErrorCode errorCode = e.getErrorCode(); diff --git a/src/main/java/com/thirdparty/ticketing/domain/seat/controller/SeatController.java b/src/main/java/com/thirdparty/ticketing/domain/seat/controller/SeatController.java index 6d2e6e45..71852106 100644 --- a/src/main/java/com/thirdparty/ticketing/domain/seat/controller/SeatController.java +++ b/src/main/java/com/thirdparty/ticketing/domain/seat/controller/SeatController.java @@ -20,6 +20,7 @@ public class SeatController { private final SeatService seatService; + @Waiting @GetMapping("/performances/{performanceId}/zones/{zoneId}/seats") public ResponseEntity> getSeats(@PathVariable("zoneId") long zoneId) { ItemResult seats = seatService.getSeats(zoneId); diff --git a/src/main/java/com/thirdparty/ticketing/domain/ticket/controller/TicketController.java b/src/main/java/com/thirdparty/ticketing/domain/ticket/controller/TicketController.java index aa21094c..90da3272 100644 --- a/src/main/java/com/thirdparty/ticketing/domain/ticket/controller/TicketController.java +++ b/src/main/java/com/thirdparty/ticketing/domain/ticket/controller/TicketController.java @@ -16,6 +16,7 @@ import com.thirdparty.ticketing.domain.ticket.dto.response.TicketElement; import com.thirdparty.ticketing.domain.ticket.service.ReservationService; import com.thirdparty.ticketing.domain.ticket.service.TicketService; +import com.thirdparty.ticketing.domain.waitingsystem.Waiting; import lombok.RequiredArgsConstructor; @@ -41,6 +42,7 @@ public ResponseEntity releaseSeat( return ResponseEntity.ok().build(); } + @Waiting @PostMapping("/seats/select") public ResponseEntity selectSeat( @LoginMember String memberEmail, @@ -49,6 +51,7 @@ public ResponseEntity selectSeat( return ResponseEntity.ok().build(); } + @Waiting @PostMapping("/tickets") public ResponseEntity reservationTicket( @LoginMember String memberEmail, diff --git a/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/DebounceAspect.java b/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/DebounceAspect.java index 57dfe956..67fdf256 100644 --- a/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/DebounceAspect.java +++ b/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/DebounceAspect.java @@ -18,6 +18,7 @@ public class DebounceAspect { private static final String DEBOUNCE_KEY = "debounce_performance:"; + public static final int DEBOUNCE_TIME = 5; private final ValueOperations debounce; @@ -40,7 +41,8 @@ public Object debounce(ProceedingJoinPoint joinPoint) throws Throwable { performanceId = (long) arg; } } - if (debounce.setIfAbsent(getDebounceKey(performanceId), "debounce", 10, TimeUnit.SECONDS)) { + if (debounce.setIfAbsent( + getDebounceKey(performanceId), "debounce", DEBOUNCE_TIME, TimeUnit.SECONDS)) { log.info("[waiting] 디바운스 요청 실행. 공연 ID={}", performanceId); return joinPoint.proceed(); } diff --git a/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/WaitingSystem.java b/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/WaitingSystem.java index b46d2da7..c0440f3a 100644 --- a/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/WaitingSystem.java +++ b/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/WaitingSystem.java @@ -1,17 +1,19 @@ package com.thirdparty.ticketing.domain.waitingsystem; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import com.thirdparty.ticketing.domain.common.EventPublisher; import com.thirdparty.ticketing.domain.waitingsystem.running.RunningManager; import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingManager; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public class WaitingSystem { + private final Map pollingEventCache = new ConcurrentHashMap<>(); private final WaitingManager waitingManager; private final RunningManager runningManager; private final EventPublisher eventPublisher; @@ -25,10 +27,12 @@ public void enterWaitingRoom(String email, long performanceId) { } public long getRemainingCount(String email, long performanceId) { - WaitingMember waitingMember = waitingManager.findWaitingMember(email, performanceId); + long memberWaitingCount = waitingManager.getMemberWaitingCount(email, performanceId); long runningCount = runningManager.getRunningCount(performanceId); - long remainingCount = waitingMember.getWaitingCount() - runningCount; - eventPublisher.publish(new PollingEvent(performanceId)); + long remainingCount = memberWaitingCount - runningCount; + PollingEvent pollingEvent = + pollingEventCache.computeIfAbsent(performanceId, PollingEvent::new); + eventPublisher.publish(pollingEvent); if (remainingCount <= 0) { eventPublisher.publish(new LastPollingEvent(email, performanceId)); } @@ -39,9 +43,8 @@ public void moveUserToRunning(long performanceId) { Set removeMemberEmails = runningManager.removeExpiredMemberInfo(performanceId); waitingManager.removeMemberInfo(removeMemberEmails, performanceId); long availableToRunning = runningManager.getAvailableToRunning(performanceId); - Set waitingMembers = - waitingManager.pullOutMembers(performanceId, availableToRunning); - runningManager.enterRunningRoom(performanceId, waitingMembers); + Set emails = waitingManager.pullOutMemberEmails(performanceId, availableToRunning); + runningManager.enterRunningRoom(performanceId, emails); } public void pullOutRunningMember(String email, long performanceId) { diff --git a/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/running/RunningManager.java b/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/running/RunningManager.java index b567e0c3..129e67bc 100644 --- a/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/running/RunningManager.java +++ b/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/running/RunningManager.java @@ -2,8 +2,6 @@ import java.util.Set; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; - public interface RunningManager { boolean isReadyToHandle(String email, long performanceId); @@ -11,7 +9,7 @@ public interface RunningManager { long getAvailableToRunning(long performanceId); - void enterRunningRoom(long performanceId, Set waitingMembers); + void enterRunningRoom(long performanceId, Set emails); void pullOutRunningMember(String email, long performanceId); diff --git a/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/waiting/WaitingManager.java b/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/waiting/WaitingManager.java index 41bf66e2..a2bef84b 100644 --- a/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/waiting/WaitingManager.java +++ b/src/main/java/com/thirdparty/ticketing/domain/waitingsystem/waiting/WaitingManager.java @@ -5,11 +5,11 @@ public interface WaitingManager { void enterWaitingRoom(String email, long performanceId); - WaitingMember findWaitingMember(String email, long performanceId); - - Set pullOutMembers(long performanceId, long availableToRunning); - void removeMemberInfo(String email, long performanceId); void removeMemberInfo(Set emails, long performanceId); + + long getMemberWaitingCount(String email, long performanceId); + + Set pullOutMemberEmails(long performanceId, long availableToRunning); } diff --git a/src/main/java/com/thirdparty/ticketing/global/config/WaitingConfig.java b/src/main/java/com/thirdparty/ticketing/global/config/WaitingConfig.java index 3e0edb8c..cd1330e2 100644 --- a/src/main/java/com/thirdparty/ticketing/global/config/WaitingConfig.java +++ b/src/main/java/com/thirdparty/ticketing/global/config/WaitingConfig.java @@ -4,7 +4,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.core.StringRedisTemplate; -import com.fasterxml.jackson.databind.ObjectMapper; import com.thirdparty.ticketing.domain.common.EventPublisher; import com.thirdparty.ticketing.domain.waitingsystem.WaitingAspect; import com.thirdparty.ticketing.domain.waitingsystem.WaitingSystem; @@ -43,15 +42,13 @@ public WaitingManager waitingManager( } @Bean - public RedisWaitingRoom waitingRoom( - StringRedisTemplate redisTemplate, ObjectMapper objectMapper) { - return new RedisWaitingRoom(redisTemplate, objectMapper); + public RedisWaitingRoom waitingRoom(StringRedisTemplate redisTemplate) { + return new RedisWaitingRoom(redisTemplate); } @Bean - public RedisWaitingLine waitingLine( - StringRedisTemplate redisTemplate, ObjectMapper objectMapper) { - return new RedisWaitingLine(redisTemplate, objectMapper); + public RedisWaitingLine waitingLine(StringRedisTemplate redisTemplate) { + return new RedisWaitingLine(redisTemplate); } @Bean diff --git a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/ObjectMapperUtils.java b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/ObjectMapperUtils.java deleted file mode 100644 index 226ffb4d..00000000 --- a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/ObjectMapperUtils.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.thirdparty.ticketing.global.waitingsystem; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.thirdparty.ticketing.domain.common.ErrorCode; -import com.thirdparty.ticketing.domain.common.TicketingException; - -public class ObjectMapperUtils { - - public static String writeValueAsString(ObjectMapper objectMapper, Object value) { - try { - return objectMapper.writeValueAsString(value); - } catch (JsonProcessingException e) { - throw new TicketingException(ErrorCode.WAITING_WRITE_ERROR); - } - } - - public static T readValue(ObjectMapper objectMapper, String value, Class valueType) { - try { - return objectMapper.readValue(value, valueType); - } catch (JsonProcessingException e) { - throw new TicketingException(ErrorCode.WAITING_READ_ERROR); - } - } -} diff --git a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningManager.java b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningManager.java index 9453ab0c..1c4b1409 100644 --- a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningManager.java +++ b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningManager.java @@ -3,7 +3,6 @@ import java.util.Set; import com.thirdparty.ticketing.domain.waitingsystem.running.RunningManager; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; import lombok.RequiredArgsConstructor; @@ -29,10 +28,9 @@ public long getAvailableToRunning(long performanceId) { } @Override - public void enterRunningRoom(long performanceId, Set waitingMembers) { - waitingMembers.forEach(WaitingMember::enter); - runningCounter.increment(performanceId, waitingMembers.size()); - runningRoom.enter(performanceId, waitingMembers); + public void enterRunningRoom(long performanceId, Set emails) { + runningCounter.increment(performanceId, emails.size()); + runningRoom.enter(performanceId, emails); } @Override diff --git a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningRoom.java b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningRoom.java index d917f351..33d8debe 100644 --- a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningRoom.java +++ b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningRoom.java @@ -8,7 +8,6 @@ import java.util.stream.Collectors; import com.thirdparty.ticketing.domain.waitingsystem.running.RunningRoom; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; import lombok.RequiredArgsConstructor; @@ -18,7 +17,7 @@ public class MemoryRunningRoom implements RunningRoom { private static final int MAX_MEMORY_RUNNING_ROOM_SIZE = 100; private static final int EXPIRED_MINUTE = 5; - private final ConcurrentMap> room; + private final ConcurrentMap> room; public boolean contains(String email, long performanceId) { if (!room.containsKey(performanceId)) { @@ -34,13 +33,14 @@ public long getAvailableToRunning(long performanceId) { - (room.containsKey(performanceId) ? room.get(performanceId).size() : 0)); } - public void enter(long performanceId, Set waitingMembers) { + public void enter(long performanceId, Set emails) { room.compute( performanceId, (key, room) -> { - ConcurrentMap runningRoom = + ConcurrentMap runningRoom = (room != null) ? room : new ConcurrentHashMap<>(); - waitingMembers.forEach(member -> runningRoom.put(member.getEmail(), member)); + emails.forEach( + email -> runningRoom.put(email, ZonedDateTime.now().plusSeconds(30))); return runningRoom; }); } @@ -55,15 +55,15 @@ public void pullOutRunningMember(String email, long performanceId) { } public Set removeExpiredMemberInfo(long performanceId) { - ConcurrentMap performanceRoom = room.get(performanceId); + ConcurrentMap performanceRoom = room.get(performanceId); if (performanceRoom == null) { return Set.of(); } - ZonedDateTime fiveMinutesAgo = ZonedDateTime.now().minusMinutes(EXPIRED_MINUTE); + ZonedDateTime now = ZonedDateTime.now(); Set removeMemberEmails = performanceRoom.entrySet().stream() - .filter(entry -> entry.getValue().getEnteredAt().isBefore(fiveMinutesAgo)) + .filter(entry -> entry.getValue().isBefore(now)) .map(Entry::getKey) .collect(Collectors.toSet()); removeMemberEmails.forEach(performanceRoom::remove); @@ -74,14 +74,7 @@ public void updateRunningMemberExpiredTime(String email, long performanceId) { room.computeIfPresent( performanceId, (key, room) -> { - room.computeIfPresent( - email, - (k, waitingMember) -> - new WaitingMember( - email, - performanceId, - waitingMember.getWaitingCount(), - ZonedDateTime.now().plusMinutes(5))); + room.put(email, ZonedDateTime.now().plusMinutes(EXPIRED_MINUTE)); return room; }); } diff --git a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/waiting/MemoryWaitingManager.java b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/waiting/MemoryWaitingManager.java index 7abaf606..222eb2a3 100644 --- a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/waiting/MemoryWaitingManager.java +++ b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/waiting/MemoryWaitingManager.java @@ -2,6 +2,7 @@ import java.time.ZonedDateTime; import java.util.Set; +import java.util.stream.Collectors; import com.thirdparty.ticketing.domain.common.ErrorCode; import com.thirdparty.ticketing.domain.common.TicketingException; @@ -28,18 +29,12 @@ public void enterWaitingRoom(String email, long performanceId) { } } - @Override public WaitingMember findWaitingMember(String email, long performanceId) { return waitingRoom .findWaitingMember(email, performanceId) .orElseThrow(() -> new TicketingException(ErrorCode.NOT_FOUND_WAITING_MEMBER)); } - @Override - public Set pullOutMembers(long performanceId, long availableToRunning) { - return waitingLine.pullOutMembers(performanceId, availableToRunning); - } - @Override public void removeMemberInfo(String email, long performanceId) { waitingRoom.removeMemberInfo(email, performanceId); @@ -49,4 +44,16 @@ public void removeMemberInfo(String email, long performanceId) { public void removeMemberInfo(Set emails, long performanceId) { waitingRoom.removeMemberInfo(emails, performanceId); } + + @Override + public long getMemberWaitingCount(String email, long performanceId) { + return waitingRoom.getMemberWaitingCount(email, performanceId); + } + + @Override + public Set pullOutMemberEmails(long performanceId, long availableToRunning) { + return waitingLine.pullOutMembers(performanceId, availableToRunning).stream() + .map(WaitingMember::getEmail) + .collect(Collectors.toSet()); + } } diff --git a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/waiting/MemoryWaitingRoom.java b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/waiting/MemoryWaitingRoom.java index e6365b28..6973bc08 100644 --- a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/waiting/MemoryWaitingRoom.java +++ b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/memory/waiting/MemoryWaitingRoom.java @@ -5,6 +5,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import com.thirdparty.ticketing.domain.common.ErrorCode; +import com.thirdparty.ticketing.domain.common.TicketingException; import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingRoom; @@ -47,4 +49,10 @@ public void removeMemberInfo(Set emails, long performanceId) { return room; }); } + + public long getMemberWaitingCount(String email, long performanceId) { + return findWaitingMember(email, performanceId) + .map(WaitingMember::getWaitingCount) + .orElseThrow(() -> new TicketingException(ErrorCode.NOT_FOUND_WAITING_MEMBER)); + } } diff --git a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningManager.java b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningManager.java index 39640334..323c0c61 100644 --- a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningManager.java +++ b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningManager.java @@ -3,7 +3,6 @@ import java.util.Set; import com.thirdparty.ticketing.domain.waitingsystem.running.RunningManager; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; import lombok.RequiredArgsConstructor; @@ -30,9 +29,9 @@ public long getAvailableToRunning(long performanceId) { } @Override - public void enterRunningRoom(long performanceId, Set waitingMembers) { - runningRoom.enter(performanceId, waitingMembers); - runningCounter.increment(performanceId, waitingMembers.size()); + public void enterRunningRoom(long performanceId, Set emails) { + runningCounter.increment(performanceId, emails.size()); + runningRoom.enter(performanceId, emails); } @Override diff --git a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningRoom.java b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningRoom.java index caef391f..f65a5585 100644 --- a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningRoom.java +++ b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningRoom.java @@ -10,7 +10,6 @@ import org.springframework.data.redis.core.ZSetOperations.TypedTuple; import com.thirdparty.ticketing.domain.waitingsystem.running.RunningRoom; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; public class RedisRunningRoom implements RunningRoom { @@ -34,18 +33,17 @@ public long getAvailableToRunning(long performanceId) { return MAX_RUNNING_ROOM_SIZE - runningRoom.size(getRunningRoomKey(performanceId)); } - public void enter(long performanceId, Set waitingMembers) { - if (waitingMembers.isEmpty()) { + public void enter(long performanceId, Set emails) { + if (emails.isEmpty()) { return; } ZonedDateTime minimumRunningTime = ZonedDateTime.now().plusSeconds(MINIMUM_RUNNING_TIME); Set> collect = - waitingMembers.stream() + emails.stream() .map( - member -> + email -> TypedTuple.of( - member.getEmail(), - (double) minimumRunningTime.toEpochSecond())) + email, (double) minimumRunningTime.toEpochSecond())) .collect(Collectors.toSet()); runningRoom.add(getRunningRoomKey(performanceId), collect); } diff --git a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingLine.java b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingLine.java index 253ffda2..ed71a246 100644 --- a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingLine.java +++ b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingLine.java @@ -6,49 +6,32 @@ import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ZSetOperations; +import org.springframework.data.redis.core.ZSetOperations.TypedTuple; -import com.fasterxml.jackson.databind.ObjectMapper; import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingLine; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; -import com.thirdparty.ticketing.global.waitingsystem.ObjectMapperUtils; public class RedisWaitingLine implements WaitingLine { private static final String WAITING_LINE_KEY = "waiting_line:"; private final ZSetOperations waitingLine; - private final ObjectMapper objectMapper; - public RedisWaitingLine(StringRedisTemplate redisTemplate, ObjectMapper objectMapper) { + public RedisWaitingLine(StringRedisTemplate redisTemplate) { this.waitingLine = redisTemplate.opsForZSet(); - this.objectMapper = objectMapper; } - public void enter(WaitingMember waitingMember) { - String value = ObjectMapperUtils.writeValueAsString(objectMapper, waitingMember); - waitingLine.add( - getWaitingLineKey(waitingMember.getPerformanceId()), - value, - waitingMember.getWaitingCount()); + public void enter(String email, long performanceId, long waitingCount) { + waitingLine.add(getWaitingLineKey(performanceId), email, waitingCount); } private String getWaitingLineKey(long performanceId) { return WAITING_LINE_KEY + performanceId; } - public Set pullOutMembers(long performanceId, long availableToRunning) { + public Set pullOutMembers(long performanceId, long availableToRunning) { return Optional.ofNullable( waitingLine.popMin(getWaitingLineKey(performanceId), availableToRunning)) - .map( - set -> - set.stream() - .map( - value -> - ObjectMapperUtils.readValue( - objectMapper, - value.getValue(), - WaitingMember.class)) - .collect(Collectors.toSet())) + .map(set -> set.stream().map(TypedTuple::getValue).collect(Collectors.toSet())) .orElseGet(Set::of); } } diff --git a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingManager.java b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingManager.java index 31d81510..c64f2654 100644 --- a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingManager.java +++ b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingManager.java @@ -1,12 +1,8 @@ package com.thirdparty.ticketing.global.waitingsystem.redis.waiting; -import java.time.ZonedDateTime; import java.util.Set; -import com.thirdparty.ticketing.domain.common.ErrorCode; -import com.thirdparty.ticketing.domain.common.TicketingException; import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingManager; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -23,32 +19,28 @@ public class RedisWaitingManager implements WaitingManager { public void enterWaitingRoom(String email, long performanceId) { if (waitingRoom.enter(email, performanceId)) { long waitingCount = waitingCounter.getNextCount(performanceId); - WaitingMember waitingMember = - new WaitingMember(email, performanceId, waitingCount, ZonedDateTime.now()); - waitingRoom.updateMemberInfo(waitingMember); - waitingLine.enter(waitingMember); + waitingRoom.updateMemberInfo(email, performanceId, waitingCount); + waitingLine.enter(email, performanceId, waitingCount); } } @Override - public WaitingMember findWaitingMember(String email, long performanceId) { - return waitingRoom - .findWaitingMember(email, performanceId) - .orElseThrow(() -> new TicketingException(ErrorCode.NOT_FOUND_WAITING_MEMBER)); + public void removeMemberInfo(String email, long performanceId) { + waitingRoom.removeMemberInfo(email, performanceId); } @Override - public Set pullOutMembers(long performanceId, long availableToRunning) { - return waitingLine.pullOutMembers(performanceId, availableToRunning); + public void removeMemberInfo(Set emails, long performanceId) { + waitingRoom.removeMemberInfo(emails, performanceId); } @Override - public void removeMemberInfo(String email, long performanceId) { - waitingRoom.removeMemberInfo(email, performanceId); + public long getMemberWaitingCount(String email, long performanceId) { + return waitingRoom.getMemberWaitingCount(email, performanceId); } @Override - public void removeMemberInfo(Set emails, long performanceId) { - waitingRoom.removeMemberInfo(emails, performanceId); + public Set pullOutMemberEmails(long performanceId, long availableToRunning) { + return waitingLine.pullOutMembers(performanceId, availableToRunning); } } diff --git a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingRoom.java b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingRoom.java index 45686b3d..80f625d0 100644 --- a/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingRoom.java +++ b/src/main/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingRoom.java @@ -6,47 +6,32 @@ import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.StringRedisTemplate; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; +import com.thirdparty.ticketing.domain.common.ErrorCode; +import com.thirdparty.ticketing.domain.common.TicketingException; import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingRoom; -import com.thirdparty.ticketing.global.waitingsystem.ObjectMapperUtils; public class RedisWaitingRoom implements WaitingRoom { private static final String WAITING_ROOM_KEY = "waiting_room:"; private final HashOperations waitingRoom; - private final ObjectMapper objectMapper; - public RedisWaitingRoom(StringRedisTemplate redisTemplate, ObjectMapper objectMapper) { + public RedisWaitingRoom(StringRedisTemplate redisTemplate) { waitingRoom = redisTemplate.opsForHash(); - this.objectMapper = objectMapper; } public boolean enter(String email, long performanceId) { return waitingRoom.putIfAbsent(getWaitingRoomKey(performanceId), email, email); } - public void updateMemberInfo(WaitingMember waitingMember) { - String value = ObjectMapperUtils.writeValueAsString(objectMapper, waitingMember); - waitingRoom.put( - getWaitingRoomKey(waitingMember.getPerformanceId()), - waitingMember.getEmail(), - value); + public void updateMemberInfo(String email, long performanceId, long waitingCount) { + waitingRoom.put(getWaitingRoomKey(performanceId), email, String.valueOf(waitingCount)); } private String getWaitingRoomKey(long performanceId) { return WAITING_ROOM_KEY + performanceId; } - public Optional findWaitingMember(String email, long performanceId) { - return Optional.ofNullable(waitingRoom.get(getWaitingRoomKey(performanceId), email)) - .map( - waitingMember -> - ObjectMapperUtils.readValue( - objectMapper, waitingMember, WaitingMember.class)); - } - public void removeMemberInfo(String email, long performanceId) { waitingRoom.delete(getWaitingRoomKey(performanceId), email); } @@ -57,4 +42,10 @@ public void removeMemberInfo(Set emails, long performanceId) { } waitingRoom.delete(getWaitingRoomKey(performanceId), emails.toArray(String[]::new)); } + + public long getMemberWaitingCount(String email, long performanceId) { + return Optional.ofNullable(waitingRoom.get(getWaitingRoomKey(performanceId), email)) + .map(Long::parseLong) + .orElseThrow(() -> new TicketingException(ErrorCode.NOT_FOUND_WAITING_MEMBER)); + } } diff --git a/src/test/java/com/thirdparty/ticketing/domain/waitingsystem/WaitingAspectTest.java b/src/test/java/com/thirdparty/ticketing/domain/waitingsystem/WaitingAspectTest.java index 38cc0611..75a7f067 100644 --- a/src/test/java/com/thirdparty/ticketing/domain/waitingsystem/WaitingAspectTest.java +++ b/src/test/java/com/thirdparty/ticketing/domain/waitingsystem/WaitingAspectTest.java @@ -4,7 +4,6 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import java.time.ZonedDateTime; import java.util.Set; import org.junit.jupiter.api.BeforeEach; @@ -19,7 +18,6 @@ import com.thirdparty.ticketing.domain.member.Member; import com.thirdparty.ticketing.domain.member.MemberRole; import com.thirdparty.ticketing.domain.member.service.JwtProvider; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; import com.thirdparty.ticketing.global.waitingsystem.redis.running.RedisRunningRoom; import com.thirdparty.ticketing.global.waitingsystem.redis.waiting.RedisWaitingLine; import com.thirdparty.ticketing.support.BaseIntegrationTest; @@ -101,7 +99,6 @@ void enterWaitingLine() throws Exception { // then assertThat(waitingLine.pullOutMembers(performanceId, 1)) - .map(WaitingMember::getEmail) .hasSize(1) .first() .satisfies(email -> assertThat(email).isEqualTo(member.getEmail())); @@ -120,11 +117,7 @@ void proceed_WhenRunningRoomContainsMember() throws Exception { .memberRole(MemberRole.USER) .build(); String bearerToken = getBearerToken(member); - runningRoom.enter( - performanceId, - Set.of( - new WaitingMember( - member.getEmail(), performanceId, 1, ZonedDateTime.now()))); + runningRoom.enter(performanceId, Set.of(member.getEmail())); // when ResultActions result = diff --git a/src/test/java/com/thirdparty/ticketing/domain/waitingsystem/WaitingSystemTest.java b/src/test/java/com/thirdparty/ticketing/domain/waitingsystem/WaitingSystemTest.java index aa68e865..60b18a6e 100644 --- a/src/test/java/com/thirdparty/ticketing/domain/waitingsystem/WaitingSystemTest.java +++ b/src/test/java/com/thirdparty/ticketing/domain/waitingsystem/WaitingSystemTest.java @@ -154,12 +154,11 @@ void removeExpiredMemberInfoFromWaitingRoom() throws JsonProcessingException { // given String anotherEmail = "anotherEmail@email.com"; ZonedDateTime now = ZonedDateTime.now().plusSeconds(30); - WaitingMember waitingMember = new WaitingMember(anotherEmail, performanceId, 2, now); - rawRunningRoom.add(getRunningRoomKey(performanceId), anotherEmail, now.toEpochSecond()); - rawWaitingRoom.put( - getWaitingRoomKey(performanceId), + rawRunningRoom.add( + getRunningRoomKey(performanceId), anotherEmail, - objectMapper.writeValueAsString(waitingMember)); + now.plusMinutes(1).toEpochSecond()); + rawWaitingRoom.put(getWaitingRoomKey(performanceId), anotherEmail, String.valueOf(2)); // when waitingSystem.moveUserToRunning(performanceId); @@ -223,14 +222,14 @@ void pullOutMember() { waitingManager.enterWaitingRoom(email, performanceId); WaitingMember waitingMember = new WaitingMember(email, performanceId, 1, ZonedDateTime.now()); - runningManager.enterRunningRoom(performanceId, Set.of(waitingMember)); + runningManager.enterRunningRoom(performanceId, Set.of(waitingMember.getEmail())); // when waitingSystem.pullOutRunningMember(email, performanceId); // then assertThat(runningManager.isReadyToHandle(email, performanceId)).isFalse(); - assertThatThrownBy(() -> waitingManager.findWaitingMember(email, performanceId)) + assertThatThrownBy(() -> waitingManager.getMemberWaitingCount(email, performanceId)) .isInstanceOf(TicketingException.class); } diff --git a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningManagerTest.java b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningManagerTest.java index 026029f6..229c225d 100644 --- a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningManagerTest.java +++ b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningManagerTest.java @@ -13,12 +13,10 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; - class MemoryRunningManagerTest { private MemoryRunningManager runningManager; - private ConcurrentMap> room; + private ConcurrentMap> room; private ConcurrentMap counter; @BeforeEach @@ -71,11 +69,10 @@ class GetAvailableToRunning { void returnZero_WhenLessThanZero() { // given long performanceId = 1; - Set waitingMembers = new HashSet<>(); + Set waitingMembers = new HashSet<>(); for (int i = 0; i < 150; i++) { - waitingMembers.add( - new WaitingMember( - "email" + i + "@email.com", performanceId, i, ZonedDateTime.now())); + String email = "email" + i + "@email.com"; + waitingMembers.add(email); } runningManager.enterRunningRoom(performanceId, waitingMembers); @@ -91,11 +88,10 @@ void returnZero_WhenLessThanZero() { void returnAvailable_WhenGreaterThanZero() { // given long performanceId = 1; - Set waitingMembers = new HashSet<>(); + Set waitingMembers = new HashSet<>(); for (int i = 0; i < 20; i++) { - waitingMembers.add( - new WaitingMember( - "email" + i + "@email.com", performanceId, i, ZonedDateTime.now())); + String email = "email" + i + "@email.com"; + waitingMembers.add(email); } runningManager.enterRunningRoom(performanceId, waitingMembers); @@ -111,7 +107,7 @@ void returnAvailable_WhenGreaterThanZero() { @DisplayName("작업 가능 공간 입장 호출 시") class EnterRunningRoomTest { - private Set waitingMembers; + private Set waitingMembers; private int waitingMemberCount; private long performanceId; @@ -121,9 +117,7 @@ void setUp() { performanceId = 1; waitingMembers = new HashSet<>(); for (int i = 0; i < waitingMemberCount; i++) { - waitingMembers.add( - new WaitingMember( - "email" + i + "@email.com", performanceId, i, ZonedDateTime.now())); + waitingMembers.add("email" + i + "@email.com"); } } diff --git a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningRoomTest.java b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningRoomTest.java index 4e3d15fd..495589cb 100644 --- a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningRoomTest.java +++ b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/memory/running/MemoryRunningRoomTest.java @@ -18,12 +18,10 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; - class MemoryRunningRoomTest { private MemoryRunningRoom runningRoom; - private ConcurrentMap> room; + private ConcurrentMap> room; @BeforeEach void setUp() { @@ -42,7 +40,7 @@ void true_WhenMemberContains() { long performanceId = 1; String email = "email@email.com"; room.putIfAbsent(performanceId, new ConcurrentHashMap<>()); - room.get(performanceId).putIfAbsent(email, new WaitingMember()); + room.get(performanceId).putIfAbsent(email, ZonedDateTime.now()); // when boolean contains = runningRoom.contains(email, performanceId); @@ -73,7 +71,7 @@ void doesNotShareRunningRoom_BetweenPerformances() { long performanceIdB = 2; String email = "email@email.com"; room.putIfAbsent(performanceIdA, new ConcurrentHashMap<>()); - room.get(performanceIdA).putIfAbsent(email, new WaitingMember()); + room.get(performanceIdA).putIfAbsent(email, ZonedDateTime.now()); // when boolean contains = runningRoom.contains(email, performanceIdB); @@ -96,7 +94,7 @@ void getAvailableToRunning(int membersCount, int expectAvailableToRunning) { room.putIfAbsent(performanceId, new ConcurrentHashMap<>()); for (int i = 0; i < membersCount; i++) { room.get(performanceId) - .putIfAbsent("email" + i + "@email.com", new WaitingMember()); + .putIfAbsent("email" + i + "@email.com", ZonedDateTime.now()); } // when @@ -116,19 +114,17 @@ class EnterTest { void putEmailInfo() { // given long performanceId = 1; - Set waitingMembers = new HashSet<>(); + Set waitingMembers = new HashSet<>(); for (int i = 0; i < 10; i++) { - waitingMembers.add( - new WaitingMember( - "email" + i + "@email.com", performanceId, i, ZonedDateTime.now())); + String email = "email" + i + "@email.com"; + waitingMembers.add(email); } // when runningRoom.enter(performanceId, waitingMembers); // then - String[] emails = - waitingMembers.stream().map(WaitingMember::getEmail).toArray(String[]::new); + String[] emails = waitingMembers.stream().toArray(String[]::new); // 각 이메일이 runningRoom 에 존재하는지 확인 for (String email : emails) { assertThat(runningRoom.contains(email, performanceId)).isTrue(); @@ -148,9 +144,7 @@ void pullOutRunningMember() { // given long performanceId = 1; String email = "email@email.com"; - Set waitingMembers = - Set.of(new WaitingMember(email, performanceId, 1, ZonedDateTime.now())); - runningRoom.enter(performanceId, waitingMembers); + runningRoom.enter(performanceId, Set.of(email)); assertThat(room.get(performanceId)).hasSize(1); // when @@ -166,9 +160,7 @@ void ignore_WhenNotExistsMember() { // given long performanceId = 1; String anotherEmail = "email@email.com"; - Set waitingMembers = - Set.of(new WaitingMember(anotherEmail, performanceId, 1, ZonedDateTime.now())); - runningRoom.enter(performanceId, waitingMembers); + runningRoom.enter(performanceId, Set.of(anotherEmail)); String email = "email" + 1 + "@email.com"; @@ -185,14 +177,14 @@ void ignore_WhenNotExistsMember() { class RemoveExpiredMemberInfoTest { @Test - @DisplayName("입장한지 5분이 지난 사용자 정보를 제거한다.") + @DisplayName("만료 시간이 현재 이전인 사용자는 제거한다.") void removeExpiredMemberInfo() { // given long performanceId = 1; String email = "email@email.com"; - ZonedDateTime fiveMinuteAgo = ZonedDateTime.now().minusMinutes(5).minusSeconds(1); - WaitingMember waitingMember = new WaitingMember(email, performanceId, 1, fiveMinuteAgo); - runningRoom.enter(performanceId, Set.of(waitingMember)); + ConcurrentHashMap performanceRunning = new ConcurrentHashMap<>(); + performanceRunning.put(email, ZonedDateTime.now().minusMinutes(1)); + room.put(performanceId, performanceRunning); // when runningRoom.removeExpiredMemberInfo(performanceId); @@ -202,21 +194,20 @@ void removeExpiredMemberInfo() { } @Test - @DisplayName("입장한지 5분이 지나지 않은 사용자 정보는 제거하지 않는다.") + @DisplayName("만료 시간이 현재 시간 이후인 사용자는 제거하지 않는다..") void notRemoveMemberInfo() { // given long performanceId = 1; String email = "email@email.com"; - ZonedDateTime nearFiveMinuteAgo = ZonedDateTime.now().minusMinutes(5).plusSeconds(2); - WaitingMember waitingMember = - new WaitingMember(email, performanceId, 1, nearFiveMinuteAgo); - runningRoom.enter(performanceId, Set.of(waitingMember)); + ConcurrentHashMap performanceRunning = new ConcurrentHashMap<>(); + performanceRunning.put(email, ZonedDateTime.now().plusMinutes(1)); + room.put(performanceId, performanceRunning); // when runningRoom.removeExpiredMemberInfo(performanceId); // then - assertThat(room.get(performanceId).get(email)).isEqualTo(waitingMember); + assertThat(room.get(performanceId).get(email)).isNotNull(); } } @@ -230,15 +221,15 @@ void updateRunningMemberExpiredTime() { // given long performanceId = 1; String email = "email@email.com"; - runningRoom.enter(performanceId, Set.of(new WaitingMember(email, performanceId))); + runningRoom.enter(performanceId, Set.of(email)); // when runningRoom.updateRunningMemberExpiredTime(email, performanceId); // then - WaitingMember waitingMember = room.get(performanceId).get(email); - assertThat(waitingMember.getEnteredAt()) - .isCloseTo(ZonedDateTime.now().plusMinutes(5), within(1, ChronoUnit.SECONDS)); + ZonedDateTime expiredAt = room.get(performanceId).get(email); + assertThat(expiredAt) + .isCloseTo(ZonedDateTime.now().plusMinutes(5), within(1, ChronoUnit.MINUTES)); } @Test diff --git a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/TestRedisConfig.java b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/TestRedisConfig.java index 6d6564e4..29c91bf6 100644 --- a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/TestRedisConfig.java +++ b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/TestRedisConfig.java @@ -41,12 +41,12 @@ public RedisWaitingManager waitingManager( @Bean public RedisWaitingRoom waitingRoom() { - return new RedisWaitingRoom(redisTemplate, objectMapper); + return new RedisWaitingRoom(redisTemplate); } @Bean public RedisWaitingLine waitingLine() { - return new RedisWaitingLine(redisTemplate, objectMapper); + return new RedisWaitingLine(redisTemplate); } @Bean diff --git a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningManagerTest.java b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningManagerTest.java index 52724c1a..2d2ac091 100644 --- a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningManagerTest.java +++ b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningManagerTest.java @@ -2,7 +2,6 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.time.ZonedDateTime; import java.util.HashSet; import java.util.Set; @@ -15,7 +14,6 @@ import org.springframework.data.redis.core.ValueOperations; import org.springframework.data.redis.core.ZSetOperations; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; import com.thirdparty.ticketing.support.BaseIntegrationTest; class RedisRunningManagerTest extends BaseIntegrationTest { @@ -83,11 +81,10 @@ class GetAvailableToRunning { void returnZero_WhenLessThanZero() { // given long performanceId = 1; - Set waitingMembers = new HashSet<>(); + Set waitingMembers = new HashSet<>(); for (int i = 0; i < 150; i++) { - waitingMembers.add( - new WaitingMember( - "email" + i + "@email.com", performanceId, i, ZonedDateTime.now())); + String email = "email" + i + "@email.com"; + waitingMembers.add(email); } runningManager.enterRunningRoom(performanceId, waitingMembers); @@ -103,11 +100,10 @@ void returnZero_WhenLessThanZero() { void returnAvailable_WhenGreaterThanZero() { // given long performanceId = 1; - Set waitingMembers = new HashSet<>(); + Set waitingMembers = new HashSet<>(); for (int i = 0; i < 20; i++) { - waitingMembers.add( - new WaitingMember( - "email" + i + "@email.com", performanceId, i, ZonedDateTime.now())); + String email = "email" + i + "@email.com"; + waitingMembers.add(email); } runningManager.enterRunningRoom(performanceId, waitingMembers); @@ -123,7 +119,7 @@ void returnAvailable_WhenGreaterThanZero() { @DisplayName("작업 가능 공간 입장 호출 시") class EnterRunningRoomTest { - private Set waitingMembers; + private Set waitingMembers; private int waitingMemberCount; private long performanceId; @@ -133,9 +129,8 @@ void setUp() { performanceId = 1; waitingMembers = new HashSet<>(); for (int i = 0; i < waitingMemberCount; i++) { - waitingMembers.add( - new WaitingMember( - "email" + i + "@email.com", performanceId, i, ZonedDateTime.now())); + String email = "email" + i + "@email.com"; + waitingMembers.add(email); } } diff --git a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningRoomTest.java b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningRoomTest.java index 38a1463f..860db16b 100644 --- a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningRoomTest.java +++ b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/running/RedisRunningRoomTest.java @@ -25,7 +25,6 @@ import org.springframework.data.redis.core.ZSetOperations; import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; import com.thirdparty.ticketing.support.BaseIntegrationTest; class RedisRunningRoomTest extends BaseIntegrationTest { @@ -134,19 +133,16 @@ class EnterTest { void putEmailInfo() { // given long performanceId = 1; - Set waitingMembers = new HashSet<>(); + Set waitingMembers = new HashSet<>(); for (int i = 0; i < 10; i++) { - waitingMembers.add( - new WaitingMember( - "email" + i + "@email.com", performanceId, i, ZonedDateTime.now())); + waitingMembers.add("email" + i + "@email.com"); } // when runningRoom.enter(performanceId, waitingMembers); // then - String[] emails = - waitingMembers.stream().map(WaitingMember::getEmail).toArray(String[]::new); + String[] emails = waitingMembers.stream().toArray(String[]::new); List score = rawRunningRoom.score(getRunningRoomKey(performanceId), emails); assertThat(score).allSatisfy(value -> assertThat(value).isNotNull()); } @@ -157,11 +153,9 @@ void test() { // given long performanceId = 1; String email = "email@email.com"; - Set waitingMembers = - Set.of(new WaitingMember(email, performanceId, 1, ZonedDateTime.now())); // when - runningRoom.enter(performanceId, waitingMembers); + runningRoom.enter(performanceId, Set.of(email)); // then Double score = rawRunningRoom.score(getRunningRoomKey(performanceId), email); @@ -185,9 +179,7 @@ void pullOutRunningMember() { // given long performanceId = 1; String email = "email@email.com"; - Set waitingMembers = - Set.of(new WaitingMember(email, performanceId, 1, ZonedDateTime.now())); - runningRoom.enter(performanceId, waitingMembers); + runningRoom.enter(performanceId, Set.of(email)); // when runningRoom.pullOutRunningMember(email, performanceId); @@ -202,8 +194,7 @@ void ignore_WhenNotExistsMember() { // given long performanceId = 1; String anotherEmail = "email@email.com"; - Set waitingMembers = - Set.of(new WaitingMember(anotherEmail, performanceId, 1, ZonedDateTime.now())); + Set waitingMembers = Set.of(anotherEmail); runningRoom.enter(performanceId, waitingMembers); String email = "email" + 1 + "@email.com"; @@ -280,7 +271,7 @@ void updateRunningMemberExpiredTime() { // given long performanceId = 1; String email = "email@email.com"; - runningRoom.enter(performanceId, Set.of(new WaitingMember(email, performanceId))); + runningRoom.enter(performanceId, Set.of(email)); // when runningRoom.updateRunningMemberExpiredTime(email, performanceId); diff --git a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingLineTest.java b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingLineTest.java index 3feb1fa8..7a5d5561 100644 --- a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingLineTest.java +++ b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingLineTest.java @@ -2,7 +2,6 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -15,9 +14,7 @@ import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ZSetOperations; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; import com.thirdparty.ticketing.support.BaseIntegrationTest; class RedisWaitingLineTest extends BaseIntegrationTest { @@ -35,7 +32,7 @@ void setUp() { redisTemplate.getConnectionFactory().getConnection().serverCommands().flushAll(); } - private String getWaitingLineKey(String performanceId) { + private String getWaitingLineKey(long performanceId) { return WAITING_LINE_KEY + performanceId; } @@ -52,53 +49,40 @@ void setUp() { @Test @DisplayName("사용자를 대기열에 추가한다.") - void addWaitingLine() throws JsonProcessingException { + void addWaitingLine() { // given - String performanceId = "1"; - long waitingCounter = 1; - WaitingMember waitingMember = new WaitingMember("email@email.com", performanceId); - waitingMember.updateWaitingInfo(waitingCounter, ZonedDateTime.now()); + long performanceId = 1; + long waitingCount = 1; + String email = "email@email.com"; // when - waitingLine.enter(waitingMember); + waitingLine.enter(email, performanceId, waitingCount); // then String performanceWaitingLineKey = getWaitingLineKey(performanceId); assertThat(rawWaitingLine.size(performanceWaitingLineKey)).isEqualTo(1); assertThat(rawWaitingLine.popMax(performanceWaitingLineKey).getValue()) - .isEqualTo(objectMapper.writeValueAsString(waitingMember)); + .isEqualTo(email); } @Test @DisplayName("사용자를 순차적으로 대기열에 추가한다.") void addWaitingLineSequentially() { // given - String performanceId = "1"; - List waitingMembers = new ArrayList<>(); + long performanceId = 1; + List memberEmails = new ArrayList<>(); int waitedMemberCount = 5; for (int i = 0; i < waitedMemberCount; i++) { - waitingMembers.add(new WaitingMember("email" + i + "@email.com", performanceId)); + memberEmails.add("email" + i + "@email.com"); } // when for (int i = 0; i < waitedMemberCount; i++) { - WaitingMember waitingMember = waitingMembers.get(i); - waitingMember.updateWaitingInfo(i, ZonedDateTime.now()); - waitingLine.enter(waitingMember); + waitingLine.enter(memberEmails.get(i), performanceId, waitedMemberCount); } // then - List expected = - waitingMembers.stream() - .map( - member -> { - try { - return objectMapper.writeValueAsString(member); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - }) - .toList(); + List expected = memberEmails.stream().toList(); String performanceWaitingLineKey = getWaitingLineKey(performanceId); Set values = rawWaitingLine.range(performanceWaitingLineKey, 0, Integer.MAX_VALUE); @@ -110,24 +94,21 @@ void addWaitingLineSequentially() { @DisplayName("서로 다른 공연은 같은 대기열을 공유하지 않는다.") void notSharedWaitingLine() { // given - String performanceAId = "1"; - int performanceAWaitedMemberCount = 5; - String performanceBId = "2"; - int performanceBWaitedMemberCount = 10; + long performanceAId = 1; + int countA = 5; + + long performanceBId = 2; + int countB = 10; // when - for (int i = 0; i < performanceAWaitedMemberCount; i++) { - WaitingMember waitingMember = - new WaitingMember("email" + i + "@email.com", performanceAId); - waitingMember.updateWaitingInfo(i, ZonedDateTime.now()); - waitingLine.enter(waitingMember); + for (int i = 0; i < countA; i++) { + String email = "email" + i + "@email.com"; + waitingLine.enter(email, performanceAId, i); } - for (int i = 0; i < performanceBWaitedMemberCount; i++) { - WaitingMember waitingMember = - new WaitingMember("email" + i + "@email.com", performanceBId); - waitingMember.updateWaitingInfo(i, ZonedDateTime.now()); - waitingLine.enter(waitingMember); + for (int i = countA; i < countA + countB; i++) { + String email = "email" + i * 10 + "@email.com"; + waitingLine.enter(email, performanceBId, i); } // then @@ -138,8 +119,8 @@ void notSharedWaitingLine() { assertThat(performanceAWaitedMembers) .doesNotContainAnyElementsOf(performanceBWaitedMembers); - assertThat(performanceAWaitedMembers).hasSize(performanceAWaitedMemberCount); - assertThat(performanceBWaitedMembers).hasSize(performanceBWaitedMemberCount); + assertThat(performanceAWaitedMembers).hasSize(countA); + assertThat(performanceBWaitedMembers).hasSize(countB); } } @@ -153,20 +134,20 @@ void pullOutMembers_LowestWaitingCount() { // given long performanceId = 1; int memberCount = 20; + List waitingMembers = new ArrayList<>(); for (int i = 1; i <= memberCount; i++) { - WaitingMember waitingMember = - new WaitingMember( - "email" + i + "@email.com", performanceId, i, ZonedDateTime.now()); - waitingLine.enter(waitingMember); + String email = "email" + i + "@email.com"; + waitingLine.enter(email, performanceId, i); + waitingMembers.add(email); } // when - Set waitingMembers = waitingLine.pullOutMembers(performanceId, 5); + Set emails = waitingLine.pullOutMembers(performanceId, 5); // then - assertThat(waitingMembers) - .map(WaitingMember::getWaitingCount) - .containsExactlyInAnyOrder(1L, 2L, 3L, 4L, 5L); + waitingMembers.stream().limit(5); + assertThat(emails) + .containsExactlyInAnyOrderElementsOf(waitingMembers.stream().limit(5).toList()); } @Test @@ -175,21 +156,18 @@ void whenAvailableToRunningIsGraterThanRunningLineSize() { // given long performanceId = 1; int memberCount = 5; + List waitingMembers = new ArrayList<>(); for (int i = 1; i <= memberCount; i++) { - WaitingMember waitingMember = - new WaitingMember( - "email" + i + "@email.com", performanceId, i, ZonedDateTime.now()); - waitingLine.enter(waitingMember); + String email = "email" + i + "@email.com"; + waitingLine.enter(email, performanceId, i); + waitingMembers.add(email); } // when - Set waitingMembers = - waitingLine.pullOutMembers(performanceId, memberCount + 20); + Set emails = waitingLine.pullOutMembers(performanceId, memberCount + 20); // then - assertThat(waitingMembers) - .map(WaitingMember::getWaitingCount) - .containsExactlyInAnyOrder(1L, 2L, 3L, 4L, 5L); + assertThat(emails).containsExactlyInAnyOrderElementsOf(waitingMembers); } @Test @@ -199,10 +177,10 @@ void whenEmpty() { long performanceId = 1; // when - Set waitingMembers = waitingLine.pullOutMembers(performanceId, 20); + Set emails = waitingLine.pullOutMembers(performanceId, 20); // then - assertThat(waitingMembers).isEmpty(); + assertThat(emails).isEmpty(); } } } diff --git a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingManagerTest.java b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingManagerTest.java index f353ab34..ecbdcfe0 100644 --- a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingManagerTest.java +++ b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingManagerTest.java @@ -1,7 +1,6 @@ package com.thirdparty.ticketing.global.waitingsystem.redis.waiting; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchException; import java.util.Optional; import java.util.Set; @@ -19,11 +18,6 @@ import org.springframework.data.redis.core.ZSetOperations; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.thirdparty.ticketing.domain.common.ErrorCode; -import com.thirdparty.ticketing.domain.common.TicketingException; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; -import com.thirdparty.ticketing.global.waitingsystem.ObjectMapperUtils; import com.thirdparty.ticketing.support.BaseIntegrationTest; class RedisWaitingManagerTest extends BaseIntegrationTest { @@ -32,8 +26,6 @@ class RedisWaitingManagerTest extends BaseIntegrationTest { @Autowired private StringRedisTemplate redisTemplate; - @Autowired private ObjectMapper objectMapper; - @BeforeEach void setUp() { redisTemplate.getConnectionFactory().getConnection().serverCommands().flushAll(); @@ -74,12 +66,10 @@ void addMemberToWaitingRoom() { String value = rawWaitingRoom.get(getWaitingRoomKey(performanceId), email); assertThat(Optional.ofNullable(value)) .isNotEmpty() - .map(v -> ObjectMapperUtils.readValue(objectMapper, v, WaitingMember.class)) .get() .satisfies( - member -> { - assertThat(member.getPerformanceId()).isEqualTo(performanceId); - assertThat(member.getEmail()).isEqualTo(email); + waitingCount -> { + assertThat(waitingCount).isEqualTo("1"); }); } @@ -99,9 +89,8 @@ void doNotAdd_ifMemberExists() throws JsonProcessingException { rawWaitingLine.range(getWaitingLineKey(performanceId), 0, Integer.MAX_VALUE); assertThat(values) .hasSize(1) - .map(value -> objectMapper.readValue(value, WaitingMember.class)) .first() - .satisfies(member -> assertThat(member.getWaitingCount()).isEqualTo(1)); + .satisfies(waitingMember -> assertThat(waitingMember).isEqualTo(email)); } @Test @@ -152,46 +141,4 @@ void enter() throws InterruptedException { assertThat(rawWaitingRoom.entries(getWaitingRoomKey(performanceId))).hasSize(1); } } - - @Nested - @DisplayName("대기중인 사용자 조회 시") - class FindWaitingMemberTest { - - @Test - @DisplayName("사용자가 존재하면 반환한다.") - void returnWaitingMember() { - // given - long performanceId = 1; - String email = "email@email.com"; - waitingManager.enterWaitingRoom(email, performanceId); - - // when - WaitingMember waitingMember = waitingManager.findWaitingMember(email, performanceId); - - // then - assertThat(waitingMember.getEmail()).isEqualTo(email); - assertThat(waitingMember.getPerformanceId()).isEqualTo(performanceId); - } - - @Test - @DisplayName("예외(NOT_FOUND_WAITING_MEMBER): 사용자가 존재하지 않으면") - void notFoundWaitingMember() { - // given - long performanceId = 1; - String email = "email@email.com"; - - // when - Exception exception = - catchException(() -> waitingManager.findWaitingMember(email, performanceId)); - - // then - assertThat(exception) - .isInstanceOf(TicketingException.class) - .extracting(e -> ((TicketingException) e).getErrorCode()) - .satisfies( - errorCode -> { - assertThat(errorCode).isEqualTo(ErrorCode.NOT_FOUND_WAITING_MEMBER); - }); - } - } } diff --git a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingRoomTest.java b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingRoomTest.java index 7674f027..dc9daf24 100644 --- a/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingRoomTest.java +++ b/src/test/java/com/thirdparty/ticketing/global/waitingsystem/redis/waiting/RedisWaitingRoomTest.java @@ -1,9 +1,9 @@ package com.thirdparty.ticketing.global.waitingsystem.redis.waiting; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.catchException; -import java.time.ZonedDateTime; import java.util.Optional; import java.util.Set; @@ -15,9 +15,7 @@ import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.StringRedisTemplate; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.thirdparty.ticketing.domain.waitingsystem.waiting.WaitingMember; -import com.thirdparty.ticketing.global.waitingsystem.ObjectMapperUtils; +import com.thirdparty.ticketing.domain.common.TicketingException; import com.thirdparty.ticketing.support.BaseIntegrationTest; class RedisWaitingRoomTest extends BaseIntegrationTest { @@ -26,8 +24,6 @@ class RedisWaitingRoomTest extends BaseIntegrationTest { @Autowired private StringRedisTemplate redisTemplate; - @Autowired private ObjectMapper objectMapper; - private HashOperations rawWaitingRoom; private String getWaitingRoomKey(long performanceId) { @@ -90,73 +86,22 @@ void updateWaitingMember() { long performanceId = 1; long waitingCount = 1; boolean enter = waitingRoom.enter(email, performanceId); - WaitingMember waitingMember = - new WaitingMember(email, performanceId, waitingCount, ZonedDateTime.now()); // when - waitingRoom.updateMemberInfo(waitingMember); + waitingRoom.updateMemberInfo(email, performanceId, waitingCount); // then String value = rawWaitingRoom.get(getWaitingRoomKey(performanceId), email); assertThat(Optional.ofNullable(value)) .isNotEmpty() - .map(v -> ObjectMapperUtils.readValue(objectMapper, v, WaitingMember.class)) .get() .satisfies( - member -> { - assertThat(member.getEmail()).isEqualTo(email); - assertThat(member.getPerformanceId()).isEqualTo(performanceId); - assertThat(member.getWaitingCount()).isEqualTo(waitingCount); + count -> { + assertThat(count).isEqualTo(String.valueOf(waitingCount)); }); } } - @Nested - @DisplayName("대기 중인 사용자 조회 시") - class FindWaitingMemberTest { - - @Test - @DisplayName("사용자가 존재하면 반환한다.") - void returnWaitingMember() { - // given - String email = "email@email.com"; - long performanceId = 1; - waitingRoom.enter(email, performanceId); - waitingRoom.updateMemberInfo( - new WaitingMember(email, performanceId, 1, ZonedDateTime.now())); - - // when - Optional optionalWaitingMember = - waitingRoom.findWaitingMember(email, performanceId); - - // then - assertThat(optionalWaitingMember) - .isNotEmpty() - .get() - .satisfies( - waitingMember -> { - assertThat(waitingMember.getEmail()).isEqualTo(email); - assertThat(waitingMember.getPerformanceId()) - .isEqualTo(performanceId); - }); - } - - @Test - @DisplayName("사용자가 존재하지 않으면 빈 값을 반환한다.") - void returnEmpty() { - // given - String email = "email@email.com"; - long performanceId = 1; - - // when - Optional optionalWaitingMember = - waitingRoom.findWaitingMember(email, performanceId); - - // then - assertThat(optionalWaitingMember).isEmpty(); - } - } - @Nested @DisplayName("대기방 사용자 정보 제거 호출 시") class removeMemberInfoTest { @@ -173,7 +118,8 @@ void removeMemberInfo() { waitingRoom.removeMemberInfo(email, performanceId); // then - assertThat(waitingRoom.findWaitingMember(email, performanceId)).isEmpty(); + assertThatThrownBy(() -> waitingRoom.getMemberWaitingCount(email, performanceId)) + .isInstanceOf(TicketingException.class); } @Test @@ -190,7 +136,8 @@ void ignore_WhenNotExistsMemberInfo() { waitingRoom.removeMemberInfo(email, performanceId); // then - assertThat(waitingRoom.findWaitingMember(email, performanceId)).isEmpty(); + assertThatThrownBy(() -> waitingRoom.getMemberWaitingCount(email, performanceId)) + .isInstanceOf(TicketingException.class); } @Test @@ -204,7 +151,8 @@ void ignore_WhenNotExistsWaitingRoom() { waitingRoom.removeMemberInfo(email, performanceId); // then - assertThat(waitingRoom.findWaitingMember(email, performanceId)).isEmpty(); + assertThatThrownBy(() -> waitingRoom.getMemberWaitingCount(email, performanceId)) + .isInstanceOf(TicketingException.class); } } @@ -226,8 +174,10 @@ void removeMemberInfo() { waitingRoom.removeMemberInfo(Set.of(email, email2), performanceId); // then - assertThat(waitingRoom.findWaitingMember(email, performanceId)).isEmpty(); - assertThat(waitingRoom.findWaitingMember(email2, performanceId)).isEmpty(); + assertThatThrownBy(() -> waitingRoom.getMemberWaitingCount(email, performanceId)) + .isInstanceOf(TicketingException.class); + assertThatThrownBy(() -> waitingRoom.getMemberWaitingCount(email2, performanceId)) + .isInstanceOf(TicketingException.class); } @Test