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

Develop #36

Merged
merged 6 commits into from
Jan 20, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ public void setTimezoneToSeoul() {
@PostConstruct
@Profile({"!test"})
public void setDynamoDB() {

CreateTableRequest createAuction =
dynamoDBMapper
.generateCreateTableRequest(Auction.class)
Expand Down Expand Up @@ -73,17 +72,4 @@ public void setDynamoDB() {
TableUtils.createTableIfNotExists(dynamoDB, createBidHistory);
TableUtils.createTableIfNotExists(dynamoDB, createAuctionHistory);
}

@PreDestroy
@Profile({"!test","!prod"})
public void deleteDB() {
TableUtils.deleteTableIfExists(
dynamoDB, dynamoDBMapper.generateDeleteTableRequest(Auction.class));

TableUtils.deleteTableIfExists(
dynamoDB, dynamoDBMapper.generateDeleteTableRequest(BidHistory.class));

TableUtils.deleteTableIfExists(
dynamoDB, dynamoDBMapper.generateDeleteTableRequest(AuctionHistory.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
public enum ChatCommand {
MESSAGE,
START,
BIDDING
BIDDING,
AUCTION_CLOSE,
TIME_SYNC,
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ public class ChatPayload<T> {
private T data;

public static <T> ChatPayload<T> of(ChatCommand command, T data) {
return (ChatPayload<T>) ChatPayload.<T>builder().command(command).data(data).build();
return ChatPayload.<T>builder().command(command).data(data).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.dailyon.auctionservice.chat.scheduler;

import com.dailyon.auctionservice.chat.response.ChatCommand;
import com.dailyon.auctionservice.chat.response.ChatPayload;
import com.dailyon.auctionservice.controller.ChatHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import reactor.core.Disposable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Duration;

@Slf4j
@Configuration
@EnableScheduling
public class ChatScheduler implements SchedulingConfigurer {

private final ThreadPoolTaskScheduler taskScheduler;
private final ChatHandler chatHandler;
private long countdown = 5 * 60 * 1000;
private Disposable jobDisposable;

public ChatScheduler(ChatHandler chatHandler) {
taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.initialize();
this.chatHandler = chatHandler;
}

@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setTaskScheduler(taskScheduler);
}

public void startJob() {
if (this.jobDisposable == null || this.jobDisposable.isDisposed()) {
this.jobDisposable =
Flux.interval(Duration.ofSeconds(1)).flatMap(it -> executeJob()).subscribe();
}
}

public void stopJob() {
if (this.jobDisposable != null && !this.jobDisposable.isDisposed()) {
this.jobDisposable.dispose();
}
}

public Mono<Void> executeJob() {
synchronized (this) { // 동기화 블록 시작
updateCountdown();
if (countdown <= 0) {
countdown = 0;
return sendCloseCommand()
.doFinally(signalType -> stopJob()); // sendCloseCommand()가 완전히 실행된 후에 stopJob()을 호출
} else {
return sendTimeSyncCommand();
}
} // 동기화 블록 끝
}

private void updateCountdown() {
countdown -= 1000;
if (countdown <= 0) {
countdown = 0;
}
}

private Mono<Void> sendCloseCommand() {
ChatPayload<Object> payload = ChatPayload.of(ChatCommand.AUCTION_CLOSE, null);
return chatHandler.broadCast(payload).then();
}

private Mono<Void> sendTimeSyncCommand() {
ChatPayload<Long> payload = ChatPayload.of(ChatCommand.TIME_SYNC, countdown);
return chatHandler.broadCast(payload).then();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,21 @@ public class BidAdminController {

private final BidFacade bidFacade;

@GetMapping("/bids/start")
public Mono<Void> start(@RequestHeader(name = "role") String role) {
return bidFacade.start();
// 경매 시작
@PatchMapping("/bids/start/{auctionId}")
public Mono<Void> start(
@RequestHeader(name = "role") String role,
@PathVariable String auctionId
) {
return bidFacade.start(auctionId);
}

// 경매 종료
@PatchMapping("/bids/end/{auctionId}")
public Mono<Void> end(
@RequestHeader(name = "role") String role,
@PathVariable String auctionId
) {
return bidFacade.end(auctionId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class BidApiController {
@PostMapping("")
public Mono<Long> bidding(
@RequestHeader("memberId") String memberId, @RequestBody CreateBidRequest request) {
log.info("isInput : {}", request.isInputCheck());
return bidFacade.createBid(request, memberId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public Mono<Void> biddingBroadCast(ChatPayload chatPayload) {
.then();
}

public Mono<Void> sendStart(ChatPayload chatPayload) {
public Mono<Void> broadCast(ChatPayload chatPayload) {
return objectStringConverter
.objectToString(chatPayload)
.flatMap(redisChatMessagePublisher::publishChatMessage)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.dailyon.auctionservice.dto.request;

import com.dailyon.auctionservice.document.BidHistory;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.*;

@Getter
@Builder
Expand All @@ -15,6 +12,7 @@ public class CreateBidRequest {
private String round;
private String nickname;
private Long bidAmount;
private boolean inputCheck;

public BidHistory toEntity(String memberId) {
BidHistory.PrimaryKey key = BidHistory.PrimaryKey.createKey(memberId);
Expand Down
18 changes: 16 additions & 2 deletions src/main/java/com/dailyon/auctionservice/facade/BidFacade.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.dailyon.auctionservice.chat.response.ChatCommand;
import com.dailyon.auctionservice.chat.response.ChatPayload;
import com.dailyon.auctionservice.chat.scheduler.ChatScheduler;
import com.dailyon.auctionservice.controller.ChatHandler;
import com.dailyon.auctionservice.document.Auction;
import com.dailyon.auctionservice.dto.request.CreateBidRequest;
Expand All @@ -22,6 +23,7 @@ public class BidFacade {
private final BidService bidService;
private final AuctionService auctionService;
private final ChatHandler chatHandler;
private final ChatScheduler scheduler;

public Mono<Long> createBid(CreateBidRequest request, String memberId) {
Auction auction = auctionService.readAuction(request.getAuctionId());
Expand All @@ -39,8 +41,20 @@ public Mono<Long> createBid(CreateBidRequest request, String memberId) {
}));
}

public Mono<Void> start() {
public Mono<Void> start(String auctionId) {
ChatPayload<Object> payload = ChatPayload.of(ChatCommand.START, null);
return chatHandler.sendStart(payload);
return auctionService
.startAuction(auctionId)
.flatMap(
auction -> {
chatHandler.broadCast(payload);
scheduler.startJob();
return Mono.empty();
});
}

public Mono<Void> end(String auctionId) {
ChatPayload<Object> payload = ChatPayload.of(ChatCommand.AUCTION_CLOSE, null);
return auctionService.endAuction(auctionId).flatMap(auction -> chatHandler.broadCast(payload));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Range;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.data.redis.core.ReactiveZSetOperations;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
Expand All @@ -31,7 +32,7 @@ public ReactiveRedisRepository(
this.reactiveRedisTemplate = reactiveRedisTemplate;
}

public Mono<Double> save(BidHistory history, Auction auction) {
public Mono<Double> save(BidHistory history, Auction auction, boolean isInput) {
String key = generateKey(history.getAuctionId());
BidInfo bidInfo = BidInfo.from(history);
long lowerBound = 0L;
Expand All @@ -41,8 +42,13 @@ public Mono<Double> save(BidHistory history, Auction auction) {
.flatMap(
rank -> {
if (rank >= lowerBound && rank <= upperBound) {
// value가 원하는 범위 내에 있으므로, score(bidAmount)에 auction.getAskingPrice() 값을 더한다.
return reactiveRedisZSet.incrementScore(key, bidInfo, auction.getAskingPrice());
if (isInput) {
return reactiveRedisZSet.add(key, bidInfo, history.getBidAmount())
.thenReturn(history.getBidAmount().doubleValue());
} else {
// value가 원하는 범위 내에 있으므로, score(bidAmount)에 auction.getAskingPrice() 값을 더한다.
return reactiveRedisZSet.incrementScore(key, bidInfo, auction.getAskingPrice());
}
} else {
return Mono.empty();
}
Expand Down
Loading