Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
5e22823
docs : PR Template 작성
pokerbearkr May 16, 2025
eba9b06
docs : readmd.md 변경
pokerbearkr May 16, 2025
b92dabd
Merge branch 'dev' of https://github.com/pokerbearkr/nullnullTicket
kmchaejin May 16, 2025
4e3b58e
feat : entity 수정
kmchaejin May 16, 2025
f8583b0
refactor : enum 클래스 분리 및 repo에 JPA 상속
kmchaejin May 18, 2025
d4d168e
feat : create(), saveSeatInfo() 기본 틀 구현
kmchaejin May 18, 2025
fe596bb
Merge branch 'dev'
kmchaejin May 18, 2025
8a39d8a
feat : 예매상태 변경하는 메서드 구현 및 생성자 수정
kmchaejin May 18, 2025
6fa4c41
Merge branch 'dev' of https://github.com/pokerbearkr/nullnullTicket i…
kmchaejin May 18, 2025
313afde
feat : updatePrice() 메서드 구현
kmchaejin May 19, 2025
35df0c4
feat : 일정시간 후 좌석반환, 공통응답 구현
kmchaejin May 19, 2025
8a92d52
feat : reservation 도메인 예외처리
kmchaejin May 19, 2025
cd648b6
refactor : 다른 api와 중복되는 api 삭제
kmchaejin May 19, 2025
f6d925a
feat : redis 연결설정 및 예매 대기 기능 구현
kmchaejin May 20, 2025
b907826
Merge branch 'dev'
kmchaejin May 20, 2025
279b555
feat : 소켓 연결 끊겼을 때 sorted set에서 데이터 삭제하는 로직 구현
kmchaejin May 20, 2025
bbf9103
refactor : 전체 코드 리팩토링
kmchaejin May 20, 2025
c5d8529
feat : 예매취소, 예매조회 api 및 유효성 검증 구현
kmchaejin May 21, 2025
68da97f
build: .gitignore 업데이트
jiyun-im-dev May 21, 2025
d508180
refactor : 인터셉터에서 데이터 추출 방식 변경 및 주석 제거
kmchaejin May 21, 2025
b15daca
build: OAuth2 의존성 추가
jiyun-im-dev May 21, 2025
41c3467
style: DTO 클래스 이름 변경
jiyun-im-dev May 21, 2025
ff1cf7d
feat: 카카오 로그인 기능 추가
jiyun-im-dev May 21, 2025
1ce36d4
Merge branch 'dev' of https://github.com/pokerbearkr/nullnullTicket i…
jiyun-im-dev May 21, 2025
ccc5362
chore : .gitignore update
kmchaejin May 21, 2025
4dd97ca
feat : 소켓 연결 테스트코드 작성
kmchaejin May 21, 2025
ebf38d2
Merge branch 'dev'
kmchaejin May 21, 2025
d302215
chore : 테스트코드 수정
kmchaejin May 21, 2025
390cc9b
fix : 테스트코드 오류 수정, SecurityConfig oauth 설정 주석 처리
kmchaejin May 21, 2025
615ef29
Merge branch 'dev'
kmchaejin May 21, 2025
3454fba
chore : 주석 해제
kmchaejin May 21, 2025
e28ede0
chore : dev-ci.yml에 redis 설정 추가
kmchaejin May 22, 2025
bb16949
Merge branch 'dev' of https://github.com/pokerbearkr/nullnullTicket i…
jiyun-im-dev May 22, 2025
a45935b
chore : redis 버전 변경, 호스트명 변경
kmchaejin May 22, 2025
0e6dc93
feat : 티켓팅 가능 시간 체크하는 로직 추가
kmchaejin May 22, 2025
1292365
Merge branch 'dev'
kmchaejin May 22, 2025
087f585
fix : seat 테이블 컬럼 수정 반영
kmchaejin May 22, 2025
20ef6ef
feat: 네이버 로그인 구조 잡기
jiyun-im-dev May 22, 2025
68e8de8
refactor : 결제 도메인이랑 로직 연결
kmchaejin May 22, 2025
3b2a11f
Merge branch 'dev'
kmchaejin May 22, 2025
a9e8846
chore : 사용안하는 클래스 삭제
kmchaejin May 22, 2025
d56f615
refactor : 소켓 연결시 헤더에서 token 추출
kmchaejin May 22, 2025
d3bf2c3
Merge branch 'dev' of https://github.com/pokerbearkr/nullnullTicket i…
kmchaejin May 22, 2025
8196b4b
Merge branch 'dev' of https://github.com/pokerbearkr/nullnullTicket i…
kmchaejin May 22, 2025
0bb6fda
feat : 대기열 TTL을 좌석 선택 화면 접근 후부터 적용하도록 수정
kmchaejin May 22, 2025
07c3a31
feat : 예매취소시 좌석 반환
kmchaejin May 22, 2025
45ace48
feat : SeatScheduleInfo Service에 대기열 passed 여부 확인 및 좌석 선택 완료 후 queue에…
kmchaejin May 23, 2025
3466e97
Merge branch 'dev'
kmchaejin May 23, 2025
08ba4e0
Merge branch 'dev' of https://github.com/pokerbearkr/nullnullTicket i…
jiyun-im-dev May 23, 2025
a27adfc
Merge branch 'dev' of https://github.com/pokerbearkr/nullnullTicket i…
kmchaejin May 23, 2025
043cfe9
Merge branch 'dev' of https://github.com/pokerbearkr/nullnullTicket i…
kmchaejin May 23, 2025
075c532
refactor : 소켓메세지 전송할 때 body 안넣어도 되도록 수정 및 오류 해결
kmchaejin May 23, 2025
707726e
chore : 웹소켓 테스트용 text 파일 추가
kmchaejin May 23, 2025
3ac74b1
Merge branch 'dev' of https://github.com/pokerbearkr/nullnullTicket i…
kmchaejin May 23, 2025
184e1b4
Merge branch 'dev' of https://github.com/pokerbearkr/nullnullTicket i…
jiyun-im-dev May 23, 2025
e3fc7a0
refactor : 불필요한 애매 정보 생성 api 제거
crocusia May 23, 2025
1ceb711
feat : SeateSchedulerInfo 상태 업데이트 메서드, redisKey 생성 메서드 추가
crocusia May 23, 2025
1c32775
refactor : 회차별 좌석 상태 변경 메서드 적용
crocusia May 23, 2025
aec9f1f
feat: 카카오 로그인 기능 추가
jiyun-im-dev May 24, 2025
94f37d4
feat : TTL 기반 상태 변경을 위한 메서드 추가
crocusia May 24, 2025
7d9f416
feat : TTL 만료된 데이터 상태 변경을 위한 스케줄링 기능 추가
crocusia May 24, 2025
83475ee
feat : 예매 취소, 결제 완료 기능에 좌석 상태 변경 메서드 적용
crocusia May 24, 2025
d9c6e55
refactor(Seat, SeatScheduleInfo) : CustomExeption 예외로 수정
crocusia May 24, 2025
04e31da
Merge branch 'feat/oauth' of https://github.com/pokerbearkr/nullnullT…
crocusia May 25, 2025
03d7451
Merge branch 'dev'
kmchaejin May 25, 2025
c4c3a03
chore : 사용하지 않는 파일 삭제
kmchaejin May 25, 2025
8ef7b5d
Merge branch 'feat/seatScheduleInfo/refactor' of https://github.com/p…
kmchaejin May 25, 2025
018fc03
Merge branch 'dev' of https://github.com/pokerbearkr/nullnullTicket i…
kmchaejin May 25, 2025
616fc3e
fix : WebSocketTest 오류 해결
kmchaejin May 25, 2025
0d1a79c
test : addWaitingQueue() 1001명 유저 등록 테스트
kmchaejin May 25, 2025
6d18317
test : deleteSelectingQueue() 테스트 코드 작성
kmchaejin May 25, 2025
fdded9e
feat : 대기열 기능과 좌석 선택 기능 연결
kmchaejin May 26, 2025
40679fc
Merge branch 'dev'
kmchaejin May 26, 2025
f59ad77
chore : 주석 삭제
kmchaejin May 26, 2025
87e68a0
chore : 주석 삭제
kmchaejin May 26, 2025
195ad54
test : 대기번호 응답 성공 테스트
kmchaejin May 26, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public enum ErrorCode {

// queue
QUEUE_INSERT_FAIL(500, "대기열 등록을 실패했습니다."),
NOT_TICKETING_TIME(400, "예매 가능 시간이 아닙니다.");
NOT_TICKETING_TIME(400, "예매 가능 시간이 아닙니다."),
PRECONDITION_REQUIRED(400, "선행 조건이 수행되지 않았습니다.");

private HttpStatus code;
private String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,9 @@ public class CheckExpiredScheduler {

private final Set<String> keys = new HashSet<>();

// 1시간마다 티켓팅 기간인 schedule을 keys에 저장
@Scheduled(cron = "0 0 * * * *")
public void checkOpenedSchedule() {

keys.clear();

List<Long> openedSchedules = scheduleRepository.findAllByStartTimeAfterAndTicketingStartTimeBefore(
LocalDateTime.now(),
LocalDateTime.now()).stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,12 @@ public void sendWaitingNumber(String key, String username, Long scheduleId) {
String destination = "/topic/queue/" + scheduleId + "/" + username;
MyQueueInfoResponse response = new MyQueueInfoResponse(scheduleId, username, rank,
true);
messagingTemplate.convertAndSend(destination, response);

addSelectingQueue(scheduleId, username);
deleteWaitingUser(scheduleId, username);

messagingTemplate.convertAndSend(destination, response);

return;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,173 +1,192 @@
package org.example.siljeun.domain.seatscheduleinfo.service;

import jakarta.persistence.EntityNotFoundException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.siljeun.domain.reservation.exception.CustomException;
import org.example.siljeun.domain.reservation.exception.ErrorCode;
import org.example.siljeun.domain.reservation.service.WaitingQueueService;
import org.example.siljeun.domain.schedule.entity.Schedule;
import org.example.siljeun.domain.schedule.repository.ScheduleRepository;
import org.example.siljeun.domain.seat.entity.Seat;
import org.example.siljeun.domain.seat.repository.SeatRepository;
import org.example.siljeun.domain.seatscheduleinfo.repository.SeatScheduleInfoRepository;
import org.example.siljeun.domain.seatscheduleinfo.entity.SeatScheduleInfo;
import org.example.siljeun.domain.seat.enums.SeatStatus;
import org.example.siljeun.domain.seatscheduleinfo.entity.SeatScheduleInfo;
import org.example.siljeun.domain.seatscheduleinfo.repository.SeatScheduleInfoRepository;
import org.example.siljeun.domain.user.entity.User;
import org.example.siljeun.domain.user.repository.UserRepository;
import org.example.siljeun.global.lock.DistributedLock;
import org.example.siljeun.global.util.RedisKeyProvider;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class SeatScheduleInfoService {
private final SeatScheduleInfoRepository seatScheduleInfoRepository;
private final ScheduleRepository scheduleRepository;
private final RedisTemplate<String, String> redisTemplate;

@DistributedLock(key = "'seat:' + #seatScheduleInfoId")
public void selectSeat(Long userId, Long scheduleId, Long seatScheduleInfoId) {

//예외 상황 처리
SeatScheduleInfo seatScheduleInfo = seatScheduleInfoRepository.findById(seatScheduleInfoId).
orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUNT_SEAT_SCHEDULE_INFO));
private final SeatScheduleInfoRepository seatScheduleInfoRepository;
private final ScheduleRepository scheduleRepository;
private final RedisTemplate<String, String> redisTemplate;
private final WaitingQueueService waitingQueueService;
private final UserRepository userRepository;

Schedule schedule = seatScheduleInfo.getSchedule();
if(schedule.getTicketingStartTime().isAfter(LocalDateTime.now())){
throw new CustomException(ErrorCode.NOT_TICKETING_TIME);
}
@DistributedLock(key = "'seat:' + #seatScheduleInfoId")
public void selectSeat(Long userId, Long scheduleId, Long seatScheduleInfoId) {

if (!seatScheduleInfo.isAvailable()) {
throw new CustomException(ErrorCode.ALREADY_SELECTED_SEAT);
}
User user = userRepository.findById(userId)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_USER));

String redisSelectedKey = RedisKeyProvider.userSelectedSeatKey(userId, scheduleId);
if (Boolean.TRUE.equals(redisTemplate.hasKey(redisSelectedKey))) {
throw new CustomException(ErrorCode.SEAT_LIMIT_ONE_PER_USER);
}

//DB 상태 변경
seatScheduleInfo.updateSeatScheduleInfoStatus(SeatStatus.SELECTED);
seatScheduleInfoRepository.save(seatScheduleInfo);
//대기열을 거쳐서 요청했는지 검증 (정상적인 요청인지 검증)
boolean hasPassed = waitingQueueService.hasPassedWaitingQueue(scheduleId, user.getUsername());
if (!hasPassed) {
throw new CustomException(ErrorCode.PRECONDITION_REQUIRED);
}

//유저가 선점한 좌석을 Redis에 저장 (정보 조회용)
redisTemplate.opsForValue()
.set(redisSelectedKey, seatScheduleInfoId.toString());
redisTemplate.expire(redisSelectedKey, Duration.ofMinutes(5));
//예외 상황 처리
SeatScheduleInfo seatScheduleInfo = seatScheduleInfoRepository.findById(seatScheduleInfoId).
orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUNT_SEAT_SCHEDULE_INFO));

//TTL 관리를 위한 키 생성
String redisLockKey = RedisKeyProvider.seatOccupyKey(seatScheduleInfoId);
redisTemplate.opsForValue().set(redisLockKey, userId.toString());
Schedule schedule = seatScheduleInfo.getSchedule();
if (schedule.getTicketingStartTime().isAfter(LocalDateTime.now())) {
throw new CustomException(ErrorCode.NOT_TICKETING_TIME);
}

//Redis 상태 변경
updateSeatScheduleInfoStatusInRedis(scheduleId, seatScheduleInfoId, SeatStatus.SELECTED);
if (!seatScheduleInfo.isAvailable()) {
throw new CustomException(ErrorCode.ALREADY_SELECTED_SEAT);
}

//TTL 적용
applySeatLockTTL(seatScheduleInfoId, SeatStatus.SELECTED);
String redisSelectedKey = RedisKeyProvider.userSelectedSeatKey(userId, scheduleId);
if (Boolean.TRUE.equals(redisTemplate.hasKey(redisSelectedKey))) {
throw new CustomException(ErrorCode.SEAT_LIMIT_ONE_PER_USER);
}

public Map<String, String> getSeatStatusMap(Long scheduleId) {
//DB 상태 변경
seatScheduleInfo.updateSeatScheduleInfoStatus(SeatStatus.SELECTED);
seatScheduleInfoRepository.save(seatScheduleInfo);

Schedule schedule = scheduleRepository.findById(scheduleId)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_SCHEDULE));
//유저가 선점한 좌석을 Redis에 저장 (정보 조회용)
redisTemplate.opsForValue()
.set(redisSelectedKey, seatScheduleInfoId.toString());
redisTemplate.expire(redisSelectedKey, Duration.ofMinutes(5));

List<SeatScheduleInfo> seatScheduleInfos = seatScheduleInfoRepository.findAllBySchedule(schedule);
if(seatScheduleInfos.isEmpty()){
throw new CustomException(ErrorCode.NOT_FOUNT_SEAT_SCHEDULE_INFO);
}
//TTL 관리를 위한 키 생성
String redisLockKey = RedisKeyProvider.seatOccupyKey(seatScheduleInfoId);
redisTemplate.opsForValue().set(redisLockKey, userId.toString());

List<String> fieldKeys = seatScheduleInfos.stream()
.map(info -> info.getId().toString())
.toList();
//Redis 상태 변경
updateSeatScheduleInfoStatusInRedis(scheduleId, seatScheduleInfoId, SeatStatus.SELECTED);

String redisKey = RedisKeyProvider.seatStatusKey(scheduleId);
List<Object> redisStatuses = redisTemplate.opsForHash().multiGet(redisKey, new ArrayList<>(fieldKeys));
//TTL 적용
applySeatLockTTL(seatScheduleInfoId, SeatStatus.SELECTED);

Map<String, String> seatStatusMap = new HashMap<>();
for (int i = 0; i < seatScheduleInfos.size(); i++) {
SeatScheduleInfo info = seatScheduleInfos.get(i);
Object redisStatusObj = redisStatuses.get(i);
//좌석 선택 queue에서 데이터 삭제
waitingQueueService.addSelectingQueue(scheduleId, user.getUsername());
}

String status = redisStatusObj != null
? redisStatusObj.toString()
: seatScheduleInfos.get(i).getStatus().name();
public Map<String, String> getSeatStatusMap(Long scheduleId) {

seatStatusMap.put(info.getId().toString(), status);
}
Schedule schedule = scheduleRepository.findById(scheduleId)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_SCHEDULE));

return seatStatusMap;
List<SeatScheduleInfo> seatScheduleInfos = seatScheduleInfoRepository.findAllBySchedule(
schedule);
if (seatScheduleInfos.isEmpty()) {
throw new CustomException(ErrorCode.NOT_FOUNT_SEAT_SCHEDULE_INFO);
}

public void forceSeatScheduleInfoInRedis(Long scheduleId){
Schedule schedule = scheduleRepository.findById(scheduleId)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_SCHEDULE));
List<String> fieldKeys = seatScheduleInfos.stream()
.map(info -> info.getId().toString())
.toList();

List<SeatScheduleInfo> seatInfos = seatScheduleInfoRepository.findAllBySchedule(schedule);
String redisKey = RedisKeyProvider.seatStatusKey(scheduleId);
List<Object> redisStatuses = redisTemplate.opsForHash()
.multiGet(redisKey, new ArrayList<>(fieldKeys));

String redisHashKey = RedisKeyProvider.seatStatusKey(scheduleId);
Map<String, String> seatStatusMap = new HashMap<>();
Map<String, String> seatStatusMap = new HashMap<>();
for (int i = 0; i < seatScheduleInfos.size(); i++) {
SeatScheduleInfo info = seatScheduleInfos.get(i);
Object redisStatusObj = redisStatuses.get(i);

for (SeatScheduleInfo seat : seatInfos) {
seatStatusMap.put(seat.getId().toString(), seat.getStatus().name());
}
String status = redisStatusObj != null
? redisStatusObj.toString()
: seatScheduleInfos.get(i).getStatus().name();

redisTemplate.opsForHash().putAll(redisHashKey, seatStatusMap);
}
@Transactional
public void updateSeatScheduleInfoStatus(Long seatScheduleInfoId, SeatStatus seatStatus){
SeatScheduleInfo seatScheduleInfo = seatScheduleInfoRepository.findById(seatScheduleInfoId)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUNT_SEAT_SCHEDULE_INFO));
seatScheduleInfo.updateSeatScheduleInfoStatus(seatStatus);

Long scheduleId = seatScheduleInfo.getSchedule().getId();
updateSeatScheduleInfoStatusInRedis(scheduleId, seatScheduleInfoId, seatStatus);
seatStatusMap.put(info.getId().toString(), status);
}

public void updateSeatScheduleInfoStatusInRedis(Long scheduleId, Long seatScheduleInfoId, SeatStatus seatStatus){
String redisKey = RedisKeyProvider.seatStatusKey(scheduleId);
String fieldKey = seatScheduleInfoId.toString();
redisTemplate.opsForHash().put(redisKey, fieldKey, seatStatus.name());
}
return seatStatusMap;
}

public void forceSeatScheduleInfoInRedis(Long scheduleId) {
Schedule schedule = scheduleRepository.findById(scheduleId)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_SCHEDULE));

List<SeatScheduleInfo> seatInfos = seatScheduleInfoRepository.findAllBySchedule(schedule);

public void applySeatLockTTL(Long seatScheduleInfoId, SeatStatus seatStatus){
String member = seatScheduleInfoId.toString();

String seatLockkey = RedisKeyProvider.seatOccupyKey(seatScheduleInfoId);
String zsetSelectedKey = RedisKeyProvider.trackExpiresKey(SeatStatus.SELECTED.name());
String zsetHoldKey = RedisKeyProvider.trackExpiresKey(SeatStatus.HOLD.name());

Duration ttl = null;
long nowMillis = System.currentTimeMillis();

redisTemplate.opsForZSet().remove(zsetSelectedKey, member);
redisTemplate.opsForZSet().remove(zsetHoldKey, member);

switch(seatStatus){
case SELECTED:
ttl = Duration.ofMinutes(5);
redisTemplate.expire(seatLockkey, ttl);
redisTemplate.opsForZSet().add(zsetSelectedKey, member, nowMillis+ttl.toMillis());
break;
case HOLD:
ttl = Duration.ofMinutes(60);
redisTemplate.expire(seatLockkey, ttl);
redisTemplate.opsForZSet().add(zsetHoldKey, member, nowMillis+ttl.toMillis());
break;
default:
redisTemplate.persist(seatLockkey);
break;
}
String redisHashKey = RedisKeyProvider.seatStatusKey(scheduleId);
Map<String, String> seatStatusMap = new HashMap<>();

for (SeatScheduleInfo seat : seatInfos) {
seatStatusMap.put(seat.getId().toString(), seat.getStatus().name());
}

public SeatScheduleInfo findById(Long seatScheduleInfoId){
return seatScheduleInfoRepository.findById(seatScheduleInfoId)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUNT_SEAT_SCHEDULE_INFO));
redisTemplate.opsForHash().putAll(redisHashKey, seatStatusMap);
}

@Transactional
public void updateSeatScheduleInfoStatus(Long seatScheduleInfoId, SeatStatus seatStatus) {
SeatScheduleInfo seatScheduleInfo = seatScheduleInfoRepository.findById(seatScheduleInfoId)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUNT_SEAT_SCHEDULE_INFO));
seatScheduleInfo.updateSeatScheduleInfoStatus(seatStatus);

Long scheduleId = seatScheduleInfo.getSchedule().getId();
updateSeatScheduleInfoStatusInRedis(scheduleId, seatScheduleInfoId, seatStatus);
}

public void updateSeatScheduleInfoStatusInRedis(Long scheduleId, Long seatScheduleInfoId,
SeatStatus seatStatus) {
String redisKey = RedisKeyProvider.seatStatusKey(scheduleId);
String fieldKey = seatScheduleInfoId.toString();
redisTemplate.opsForHash().put(redisKey, fieldKey, seatStatus.name());
}

public void applySeatLockTTL(Long seatScheduleInfoId, SeatStatus seatStatus) {
String member = seatScheduleInfoId.toString();

String seatLockkey = RedisKeyProvider.seatOccupyKey(seatScheduleInfoId);
String zsetSelectedKey = RedisKeyProvider.trackExpiresKey(SeatStatus.SELECTED.name());
String zsetHoldKey = RedisKeyProvider.trackExpiresKey(SeatStatus.HOLD.name());

Duration ttl = null;
long nowMillis = System.currentTimeMillis();

redisTemplate.opsForZSet().remove(zsetSelectedKey, member);
redisTemplate.opsForZSet().remove(zsetHoldKey, member);

switch (seatStatus) {
case SELECTED:
ttl = Duration.ofMinutes(5);
redisTemplate.expire(seatLockkey, ttl);
redisTemplate.opsForZSet().add(zsetSelectedKey, member, nowMillis + ttl.toMillis());
break;
case HOLD:
ttl = Duration.ofMinutes(60);
redisTemplate.expire(seatLockkey, ttl);
redisTemplate.opsForZSet().add(zsetHoldKey, member, nowMillis + ttl.toMillis());
break;
default:
redisTemplate.persist(seatLockkey);
break;
}
}

public SeatScheduleInfo findById(Long seatScheduleInfoId) {
return seatScheduleInfoRepository.findById(seatScheduleInfoId)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUNT_SEAT_SCHEDULE_INFO));
}
}
Loading