Skip to content

Commit

Permalink
Merge pull request #28 from lotteon2/feat/auction-bid
Browse files Browse the repository at this point in the history
[FEAT] 입찰 임시
  • Loading branch information
wakkpu authored Jan 17, 2024
2 parents 9f152bb + 30bedf8 commit c206ef8
Show file tree
Hide file tree
Showing 11 changed files with 124 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,6 @@ public void setTimezoneToSeoul() {
@PostConstruct
@Profile({"!test"})
public void setDynamoDB() {
// TableUtils.deleteTableIfExists(
// dynamoDB, dynamoDBMapper.generateDeleteTableRequest(Auction.class));

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

TableUtils.deleteTableIfExists(
dynamoDB, dynamoDBMapper.generateDeleteTableRequest(AuctionHistory.class));
Expand All @@ -58,28 +53,40 @@ public void setDynamoDB() {
CreateTableRequest createBidHistory =
dynamoDBMapper
.generateCreateTableRequest(BidHistory.class)
.withProvisionedThroughput(new ProvisionedThroughput(1L, 1L));
.withProvisionedThroughput(new ProvisionedThroughput(1000L, 1000L));

CreateTableRequest createAuctionHistory = dynamoDBMapper
CreateTableRequest createAuctionHistory =
dynamoDBMapper
.generateCreateTableRequest(AuctionHistory.class)
.withProvisionedThroughput(new ProvisionedThroughput(1L, 1L));

createBidHistory
.getGlobalSecondaryIndexes()
.forEach(idx -> idx
.withProvisionedThroughput(new ProvisionedThroughput(1L, 1L))
.withProjection(new Projection().withProjectionType("ALL"))
);

.forEach(
idx ->
idx.withProvisionedThroughput(new ProvisionedThroughput(1000L, 1000L))
.withProjection(new Projection().withProjectionType("ALL")));
createAuctionHistory
.getGlobalSecondaryIndexes()
.forEach(idx -> idx
.withProvisionedThroughput(new ProvisionedThroughput(1L, 1L))
.withProjection(new Projection().withProjectionType("ALL"))
);

.getGlobalSecondaryIndexes()
.forEach(
idx ->
idx.withProvisionedThroughput(new ProvisionedThroughput(1L, 1L))
.withProjection(new Projection().withProjectionType("ALL")));
TableUtils.createTableIfNotExists(dynamoDB, createAuction);
TableUtils.createTableIfNotExists(dynamoDB, createBidHistory);
TableUtils.createTableIfNotExists(dynamoDB, createAuctionHistory);
}

@PreDestroy
@Profile({"!test"})
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 @@ -44,7 +44,6 @@ public Mono<Long> publishChatMessage(String message) {
String result = "EMPTY_MESSAGE";
try {
ChatPayload chatPayload = objectMapper.readValue(message, ChatPayload.class);
log.info("chat payload -> {}", chatPayload);
result = objectMapper.writeValueAsString(chatPayload);
} catch (JsonProcessingException e) {
log.error("Error converting ChatMessage {} into string", message, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.dailyon.auctionservice.chat.messaging.RedisChatMessageListener;
import com.dailyon.auctionservice.document.BidHistory;
import com.dailyon.auctionservice.dto.response.BidInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
Expand Down Expand Up @@ -64,18 +65,18 @@ ReactiveStringRedisTemplate reactiveStringRedisTemplate(
}

@Bean("reactiveRedisTemplateForBid")
public ReactiveRedisTemplate<String, BidHistory> reactiveRedisTemplate(
public ReactiveRedisTemplate<String, BidInfo> reactiveRedisTemplate(
ReactiveRedisConnectionFactory factory) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule()); // Java 8 날짜/시간 모듈 등록
objectMapper.disable(
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // 날짜를 timestamp가 아닌 ISO 형식으로 출력

Jackson2JsonRedisSerializer<BidHistory> serializer =
new Jackson2JsonRedisSerializer<>(BidHistory.class);
Jackson2JsonRedisSerializer<BidInfo> serializer =
new Jackson2JsonRedisSerializer<>(BidInfo.class);
serializer.setObjectMapper(objectMapper);
RedisSerializationContext<String, BidHistory> serializationContext =
RedisSerializationContext.<String, BidHistory>newSerializationContext(
RedisSerializationContext<String, BidInfo> serializationContext =
RedisSerializationContext.<String, BidInfo>newSerializationContext(
new StringRedisSerializer())
.value(serializer)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ public class BidAdminController {

@GetMapping("/bids/start")
public Mono<Void> start(@RequestHeader(name = "role") String role) {
bidFacade.start();
return Mono.empty();
return bidFacade.start();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public class BidApiController {
@PostMapping("")
public Mono<Long> bidding(
@RequestHeader("memberId") String memberId, @RequestBody CreateBidRequest request) {
log.info("memberId {} ", memberId);
return bidFacade.createBid(request, memberId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ public Mono<Sinks.EmitResult> sendMessage(ChatPayload chatMessage) {
}

public Mono<Void> biddingBroadCast(ChatPayload chatPayload) {
log.info("payload {}", chatPayload);
return objectStringConverter
.objectToString(chatPayload)
.flatMap(redisChatMessagePublisher::publishChatMessage)
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/com/dailyon/auctionservice/dto/response/BidInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.dailyon.auctionservice.dto.response;

import com.dailyon.auctionservice.document.BidHistory;
import lombok.*;

@ToString
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BidInfo {
private String memberId;
private String nickname;
private String auctionId;
private String round;

public static BidInfo from(BidHistory history) {
return BidInfo.builder()
.memberId(history.getMemberId())
.nickname(history.getNickname())
.auctionId(history.getAuctionId())
.round(history.getRound())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.dailyon.auctionservice.dto.response;

import com.dailyon.auctionservice.document.BidHistory;
import lombok.Builder;
import lombok.Getter;

Expand All @@ -11,12 +10,11 @@ public class TopBidderResponse {
private String nickname;
private Long bidAmount;

public static TopBidderResponse from(BidHistory bidHistory) {
public static TopBidderResponse from(BidInfo bidInfo, Long bidAmount) {
return TopBidderResponse.builder()
.memberId(bidHistory.getMemberId())
.nickname(bidHistory.getNickname())
.bidAmount(bidHistory.getBidAmount())
.memberId(bidInfo.getMemberId())
.nickname(bidInfo.getNickname())
.bidAmount(bidAmount)
.build();
}
;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public Mono<Long> createBid(CreateBidRequest request, String memberId) {

Mono<Long> bidAmountMono = bidService.create(request, memberId);
Mono<List<TopBidderResponse>> topBidderMono = bidService.getTopBidder(request, maximumWinner);

return bidAmountMono.flatMap(
bidAmount ->
topBidderMono.flatMap(
Expand All @@ -40,8 +39,8 @@ public Mono<Long> createBid(CreateBidRequest request, String memberId) {
}));
}

public void start() {
public Mono<Void> start() {
ChatPayload<Object> payload = ChatPayload.of(ChatCommand.START, null);
chatHandler.sendStart(payload);
return chatHandler.sendStart(payload);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.dailyon.auctionservice.repository;

import com.dailyon.auctionservice.document.Auction;
import com.dailyon.auctionservice.document.BidHistory;
import com.dailyon.auctionservice.dto.request.CreateBidRequest;
import com.dailyon.auctionservice.dto.response.BidInfo;
import com.dailyon.auctionservice.dto.response.TopBidderResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Profile;
import org.springframework.data.domain.Range;
Expand All @@ -13,36 +17,63 @@

import java.time.Duration;

@Slf4j
@Profile("!test")
@Repository
public class ReactiveRedisRepository {
private static final String AUCTION_KEY = "auction_id:";
private static final String ROUND_KEY = ":round:";
private final ReactiveZSetOperations reactiveRedisZSet;
private final ReactiveRedisTemplate<String, BidHistory> reactiveRedisTemplate;
private static final String MEMBER_ID = ":member_id:";
private final ReactiveZSetOperations<String, BidInfo> reactiveRedisZSet;
private final ReactiveRedisTemplate<String, BidInfo> reactiveRedisTemplate;

public ReactiveRedisRepository(
@Qualifier("reactiveRedisTemplateForBid")
ReactiveRedisTemplate<String, BidHistory> reactiveRedisTemplate) {
ReactiveRedisTemplate<String, BidInfo> reactiveRedisTemplate) {
this.reactiveRedisZSet = reactiveRedisTemplate.opsForZSet();
this.reactiveRedisTemplate = reactiveRedisTemplate;
}

public Mono<Void> save(BidHistory history) {
String key = generateKey(history.getAuctionId(), history.getRound());
public Mono<Double> save(BidHistory history, Auction auction) {
String key = generateKey(history.getAuctionId());
BidInfo bidInfo = BidInfo.from(history);
long lowerBound = 0L;
long upperBound = auction.getMaximumWinner() - 1;
return reactiveRedisZSet
.add(key, history, history.getBidAmount())
.flatMap(success -> reactiveRedisTemplate.expire(key, Duration.ofHours(1L)))
.then();
.rank(key, bidInfo)
.flatMap(
rank -> {
if (rank >= lowerBound && rank <= upperBound) {
// value가 원하는 범위 내에 있으므로, score(bidAmount)에 auction.getAskingPrice() 값을 더한다.
return reactiveRedisZSet.incrementScore(key, bidInfo, auction.getAskingPrice());
} else {
return Mono.empty();
}
})
.switchIfEmpty(
reactiveRedisZSet
.add(key, bidInfo, history.getBidAmount())
.thenReturn(history.getBidAmount().doubleValue()))
.flatMap(
bidAmount -> {
reactiveRedisTemplate.expire(key, Duration.ofHours(1L));
return Mono.just(bidAmount);
});
}

public Flux<BidHistory> getTopBidder(CreateBidRequest request, int maximum) {
String key = generateKey(request.getAuctionId(), request.getRound());
return reactiveRedisZSet.reverseRange(
key, Range.from(Range.Bound.inclusive(0L)).to(Range.Bound.inclusive((long) maximum-1)));
public Flux<TopBidderResponse> getTopBidder(CreateBidRequest request, int maximum) {
String key = generateKey(request.getAuctionId());
return reactiveRedisZSet
.reverseRange(
key,
Range.from(Range.Bound.inclusive(0L)).to(Range.Bound.inclusive((long) maximum - 1)))
.flatMap(
bidInfo ->
reactiveRedisZSet
.score(key, bidInfo)
.map(score -> TopBidderResponse.from(bidInfo, Math.round(score))));
}

private String generateKey(String auctionId, String round) {
return AUCTION_KEY + auctionId + ROUND_KEY + round;
private String generateKey(String auctionId) {
return AUCTION_KEY + auctionId;
}
}
23 changes: 15 additions & 8 deletions src/main/java/com/dailyon/auctionservice/service/BidService.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,23 @@ public class BidService {

public Mono<Long> create(CreateBidRequest request, String memberId) {
BidHistory bidHistory = request.toEntity(memberId);
return reactiveRedisRepository
.save(bidHistory)
.then(Mono.just(bidHistoryRepository.save(bidHistory)))
.map(BidHistory::getBidAmount);

return Mono.justOrEmpty(
auctionRepository
.findById(request.getAuctionId())
.orElseThrow(() -> new RuntimeException("해당 경매정보가 존재하지 않습니다.")))
.flatMap(
auction ->
reactiveRedisRepository
.save(bidHistory, auction)
.flatMap(
bidAmount -> {
bidHistoryRepository.save(bidHistory);
return Mono.just(bidAmount.longValue());
}));
}

public Mono<List<TopBidderResponse>> getTopBidder(CreateBidRequest request, int maximumWinner) {
return reactiveRedisRepository
.getTopBidder(request, maximumWinner)
.map(TopBidderResponse::from)
.collectList();
return reactiveRedisRepository.getTopBidder(request, maximumWinner).collectList();
}
}

0 comments on commit c206ef8

Please sign in to comment.