Parcourir la source

延时规则修改

hr~ il y a 3 semaines
Parent
commit
f9f2ac6423

+ 18 - 3
bid/src/main/java/cn/hobbystocks/auc/websocket/LotRealtimeWebSocketPublisher.java

@@ -5,6 +5,7 @@ import cn.hobbystocks.auc.handle.context.Live;
 import cn.hobbystocks.auc.handle.context.tradition.TraditionLive;
 import cn.hobbystocks.auc.realtime.LotRealtimePublisher;
 import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
@@ -12,6 +13,7 @@ import java.math.BigDecimal;
 import java.util.Objects;
 
 @Component
+@Slf4j
 public class LotRealtimeWebSocketPublisher implements LotRealtimePublisher {
 
     private final LotWebSocketSessionRegistry sessionRegistry;
@@ -29,6 +31,9 @@ public class LotRealtimeWebSocketPublisher implements LotRealtimePublisher {
         Lot lot = live.getLot();
         Long currentEndTime = live.getCurrentEndTime();
         Long serverTime = System.currentTimeMillis();
+        Boolean delayChanged = previousEndTime != null
+                && currentEndTime != null
+                && !Objects.equals(previousEndTime, currentEndTime);
         LotRealtimeMessage message = LotRealtimeMessage.builder()
                 .type(LotRealtimeMessage.TYPE)
                 .lotId(lot.getId())
@@ -40,10 +45,20 @@ public class LotRealtimeWebSocketPublisher implements LotRealtimePublisher {
                 .currentPrice(currentPrice(live))
                 .bidCount(lot.getBidCount())
                 .bidPersionCount(lot.getBidPersionCount())
-                .delayChanged(previousEndTime != null
-                        && currentEndTime != null
-                        && !Objects.equals(previousEndTime, currentEndTime))
+                .delayChanged(delayChanged)
                 .build();
+        log.info("lot realtime websocket publish lotId:{} auctionId:{} status:{} previousEndTime:{} currentEndTime:{} delayChanged:{} serverTime:{} timestamp:{} currentPrice:{} bidCount:{} bidPersionCount:{}",
+                lot.getId(),
+                lot.getAuctionId(),
+                lot.getStatus(),
+                previousEndTime,
+                currentEndTime,
+                delayChanged,
+                serverTime,
+                currentEndTime == null ? null : currentEndTime - serverTime,
+                currentPrice(live),
+                lot.getBidCount(),
+                lot.getBidPersionCount());
         sessionRegistry.broadcast(lot.getId(), JSON.toJSONString(message));
     }
 

+ 35 - 12
lot/src/main/java/cn/hobbystocks/auc/handle/impl/tradition/TraditionRuleHandler.java

@@ -27,16 +27,28 @@ public class TraditionRuleHandler extends AbstractTraditionRuleHandler {
 
     @Override
     protected void delay(TraditionLive traditionLive) {
-        //计算当前结束时间和剩余总计延时时间
-        long remainingAllDelayTime = defaultDelayTime(traditionLive.getRemainingAllDelayTime());
-        long onceDelayTime = Math.min(remainingAllDelayTime, defaultDelayTime(traditionLive.getTraditionRule().getOnceDelayTime()));
-        traditionLive.setRemainingAllDelayTime(remainingAllDelayTime);
+        // 没有总计延时时间时,不限制标准延时次数
+        long onceDelayTime = defaultDelayTime(traditionLive.getTraditionRule().getOnceDelayTime());
         if (onceDelayTime <= 0) {
             return;
         }
-        if ((System.currentTimeMillis() + onceDelayTime * 1000) > traditionLive.getCurrentEndTime()) {
+        if (Objects.isNull(traditionLive.getTraditionRule().getAllDelayTime())) {
+            traditionLive.setRemainingAllDelayTime(null);
+            if ((System.currentTimeMillis() + onceDelayTime * 1000) >= traditionLive.getCurrentEndTime()) {
+                traditionLive.setCurrentEndTime(traditionLive.getCurrentEndTime() + onceDelayTime * 1000);
+            }
+            return;
+        }
+
+        Long remainingAllDelayTime = defaultDelayTime(traditionLive.getRemainingAllDelayTime());
+        traditionLive.setRemainingAllDelayTime(remainingAllDelayTime);
+        if (remainingAllDelayTime <= 0) {
+            return;
+        }
+        onceDelayTime = Math.min(remainingAllDelayTime, onceDelayTime);
+        if ((System.currentTimeMillis() + onceDelayTime * 1000) >= traditionLive.getCurrentEndTime()) {
             traditionLive.setCurrentEndTime(traditionLive.getCurrentEndTime() + onceDelayTime * 1000);
-            traditionLive.setRemainingAllDelayTime(traditionLive.getRemainingAllDelayTime() - onceDelayTime);
+            traditionLive.setRemainingAllDelayTime(remainingAllDelayTime - onceDelayTime);
         }
     }
 
@@ -47,19 +59,30 @@ public class TraditionRuleHandler extends AbstractTraditionRuleHandler {
      */
     @Override
     protected void delaySync(TraditionLive traditionLive, List<Bid> bids) {
-        long allDelayTime = defaultDelayTime(traditionLive.getTraditionRule().getAllDelayTime());
+        Long allDelayTime = traditionLive.getTraditionRule().getAllDelayTime();
         long onceDelayTime = defaultDelayTime(traditionLive.getTraditionRule().getOnceDelayTime());
         traditionLive.setRemainingAllDelayTime(allDelayTime);
         if (onceDelayTime <= 0) {
             return;
         }
         for (int index = bids.size() - 1; index >= 0; index--) {
-            if ((bids.get(index).getCreateTime().getTime() + onceDelayTime * 1000) > traditionLive.getCurrentEndTime()) {
-                allDelayTime = allDelayTime - onceDelayTime;
-                traditionLive.setCurrentEndTime(traditionLive.getCurrentEndTime() + onceDelayTime * 1000);
+            if (Objects.isNull(allDelayTime)) {
+                if ((bids.get(index).getCreateTime().getTime() + onceDelayTime * 1000) >= traditionLive.getCurrentEndTime()) {
+                    traditionLive.setCurrentEndTime(traditionLive.getCurrentEndTime() + onceDelayTime * 1000);
+                }
+                traditionLive.setRemainingAllDelayTime(null);
+                continue;
             }
-            traditionLive.setRemainingAllDelayTime(allDelayTime > 0 ? allDelayTime : 0);
+            long actualDelayTime = onceDelayTime;
+            if (allDelayTime <= 0) {
+                break;
+            }
+            actualDelayTime = Math.min(allDelayTime, onceDelayTime);
+            if ((bids.get(index).getCreateTime().getTime() + actualDelayTime * 1000) >= traditionLive.getCurrentEndTime()) {
+                allDelayTime = allDelayTime - actualDelayTime;
+                traditionLive.setCurrentEndTime(traditionLive.getCurrentEndTime() + actualDelayTime * 1000);
+            }
+            traditionLive.setRemainingAllDelayTime(Math.max(allDelayTime, 0));
         }
-
     }
 }

+ 44 - 2
lot/src/main/java/cn/hobbystocks/auc/handle/impl/tradition/TraditionRuleV2Handler.java

@@ -32,7 +32,25 @@ public class TraditionRuleV2Handler extends AbstractTraditionRuleHandler {
     protected void delay(TraditionLive traditionLive) {
         //单次延迟时间(秒)
         Long onceDelayTime = traditionLive.getTraditionRule().getOnceDelayTime();
-        Long currentEndTime = Math.max((System.currentTimeMillis() + onceDelayTime * 1000L), traditionLive.getCurrentEndTime());
+        Long beforeEndTime = traditionLive.getCurrentEndTime();
+        long now = System.currentTimeMillis();
+        if (Objects.isNull(onceDelayTime) || Objects.isNull(beforeEndTime)) {
+            log.error("resetDelay addPrice skip, missing delay config lotId:{} ruleType:{} onceDelayTime:{} beforeEndTime:{} now:{}",
+                    lotId(traditionLive), ruleType(traditionLive), onceDelayTime, beforeEndTime, now);
+            return;
+        }
+        Long candidateEndTime = now + onceDelayTime * 1000L;
+        Long currentEndTime = Math.max(candidateEndTime, beforeEndTime);
+        log.info("resetDelay addPrice calculate lotId:{} ruleType:{} onceDelayTime:{} now:{} beforeEndTime:{} remainingBeforeMs:{} candidateEndTime:{} afterEndTime:{} extended:{}",
+                lotId(traditionLive),
+                ruleType(traditionLive),
+                onceDelayTime,
+                now,
+                beforeEndTime,
+                beforeEndTime - now,
+                candidateEndTime,
+                currentEndTime,
+                !Objects.equals(beforeEndTime, currentEndTime));
         traditionLive.setCurrentEndTime(currentEndTime);
     }
 
@@ -45,8 +63,32 @@ public class TraditionRuleV2Handler extends AbstractTraditionRuleHandler {
     protected void delaySync(TraditionLive traditionLive, List<Bid> bids) {
         for (int index = bids.size() - 1; index >= 0; index--) {
             Long onceDelayTime = traditionLive.getTraditionRule().getOnceDelayTime();
-            Long currentEndTime = Math.max((bids.get(index).getCreateTime().getTime() + onceDelayTime * 1000L), traditionLive.getCurrentEndTime());
+            Long beforeEndTime = traditionLive.getCurrentEndTime();
+            if (Objects.isNull(onceDelayTime) || Objects.isNull(beforeEndTime) || Objects.isNull(bids.get(index).getCreateTime())) {
+                log.error("resetDelay sync skip, missing delay data lotId:{} ruleType:{} onceDelayTime:{} beforeEndTime:{} bidId:{} bidCreateTime:{}",
+                        lotId(traditionLive), ruleType(traditionLive), onceDelayTime, beforeEndTime, bids.get(index).getId(), bids.get(index).getCreateTime());
+                continue;
+            }
+            Long candidateEndTime = bids.get(index).getCreateTime().getTime() + onceDelayTime * 1000L;
+            Long currentEndTime = Math.max(candidateEndTime, beforeEndTime);
+            log.info("resetDelay sync calculate lotId:{} bidId:{} onceDelayTime:{} bidCreateTime:{} beforeEndTime:{} candidateEndTime:{} afterEndTime:{} extended:{}",
+                    lotId(traditionLive),
+                    bids.get(index).getId(),
+                    onceDelayTime,
+                    bids.get(index).getCreateTime().getTime(),
+                    beforeEndTime,
+                    candidateEndTime,
+                    currentEndTime,
+                    !Objects.equals(beforeEndTime, currentEndTime));
             traditionLive.setCurrentEndTime(currentEndTime);
         }
     }
+
+    private Long lotId(TraditionLive traditionLive) {
+        return Objects.nonNull(traditionLive.getLot()) ? traditionLive.getLot().getId() : null;
+    }
+
+    private String ruleType(TraditionLive traditionLive) {
+        return Objects.nonNull(traditionLive.getLot()) ? traditionLive.getLot().getRuleType() : null;
+    }
 }

+ 5 - 0
lot/src/main/java/cn/hobbystocks/auc/response/LotFansResponse.java

@@ -1,5 +1,6 @@
 package cn.hobbystocks.auc.response;
 
+import com.fasterxml.jackson.annotation.JsonAlias;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -8,6 +9,7 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.math.BigDecimal;
 import java.util.Date;
 
 @Data
@@ -83,4 +85,7 @@ public class LotFansResponse {
     /** 规则内容 */
     @ApiModelProperty("规则内容")
     private String ruleContent;
+
+    @ApiModelProperty("最新价")
+    private BigDecimal lastPrice;
 }

+ 82 - 0
lot/src/main/java/cn/hobbystocks/auc/service/impl/BidServiceImpl.java

@@ -29,6 +29,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Isolation;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
@@ -79,15 +80,50 @@ public class BidServiceImpl implements IBidService
                 live = rebuildLive(bid);
             }
             Long previousEndTime = live.getCurrentEndTime();
+            log.info("addPrice live snapshot auctionId:{} lotId:{} bidAmount:{} liveClass:{} ruleType:{} liveLotStatus:{} currentEndTime:{} currentPrice:{} currentStartPrice:{} currentOnceAddPrice:{} onceDelayTime:{} round:{}",
+                    bid.getAuctionId(),
+                    bid.getLotId(),
+                    bid.getAmount(),
+                    live.getClass().getSimpleName(),
+                    ruleType(live),
+                    Objects.nonNull(live.getLot()) ? live.getLot().getStatus() : null,
+                    previousEndTime,
+                    currentPrice(live),
+                    currentStartPrice(live),
+                    currentOnceAddPrice(live),
+                    onceDelayTime(live),
+                    live.getRound());
             // 插入新的出价
             insertCurrBid(bid, live.getRound());
             // 执行addPrice方法之前已进行了拍卖状态的判断
             // 但由于是在分布式锁之外判断的 这里做二次判断 以防并发问题
             String currentStatus = ruleHandlerHolder.getCurrentStatus(live);
+            log.info("addPrice status check auctionId:{} lotId:{} currentStatus:{} previousEndTime:{} serverTime:{} remainingMs:{}",
+                    bid.getAuctionId(),
+                    bid.getLotId(),
+                    currentStatus,
+                    previousEndTime,
+                    System.currentTimeMillis(),
+                    Objects.nonNull(previousEndTime) ? previousEndTime - System.currentTimeMillis() : null);
             if (Objects.equals(Constants.LOT_STATUS_STARTING, currentStatus) || Objects.equals(Constants.LOT_STATUS_BIDDING, currentStatus)) {
                 Lot dbUpdate = Lot.builder().id(live.getLot().getId()).build();
                 LiveContext liveContext = LiveContext.builder().dbLot(dbUpdate).live(live).dbBid(bid).build();
+                Long beforeRuleEndTime = live.getCurrentEndTime();
                 ruleHandlerHolder.addPrice(liveContext); // 实时计算中。。。。
+                log.info("addPrice rule calculated auctionId:{} lotId:{} ruleType:{} onceDelayTime:{} error:{} beforeEndTime:{} afterEndTime:{} delayChanged:{} serverTime:{} remainingMs:{} currentPrice:{} currentStartPrice:{} currentOnceAddPrice:{}",
+                        bid.getAuctionId(),
+                        bid.getLotId(),
+                        ruleType(live),
+                        onceDelayTime(live),
+                        liveContext.getError(),
+                        beforeRuleEndTime,
+                        live.getCurrentEndTime(),
+                        !Objects.equals(beforeRuleEndTime, live.getCurrentEndTime()),
+                        System.currentTimeMillis(),
+                        Objects.nonNull(live.getCurrentEndTime()) ? live.getCurrentEndTime() - System.currentTimeMillis() : null,
+                        currentPrice(live),
+                        currentStartPrice(live),
+                        currentOnceAddPrice(live));
                 if (StringUtils.isEmpty(liveContext.getError())) {
                     // 到这一步 已经完成了实时数据的计算 以下代码就需要对这些计算结果落库或者更新缓存
                     runnable.run(); // 实际这里执行的是扣减积分的操作
@@ -96,6 +132,9 @@ public class BidServiceImpl implements IBidService
                     redisCache.setList(String.format(Constants.REDIS_MAP_AUC_LOT_BID_TEMPLATE, live.getLot().getId()), bidList);
                     live.getLot().setProperties(null);
                     redisCache.setCacheMapValue(String.format(Constants.REDIS_MAP_AUC_LOT_TEMPLATE, live.getLot().getAuctionId()), live.getLot().getId().toString(), live);
+                    if (Objects.nonNull(cacheMap)) {
+                        cacheMap.putLive(live);
+                    }
                     publishRealtime(live, previousEndTime);
                     // 这里发送 状态变更消息 其中同步内存中的缓存和发送IM消息给APP
                     //TODO 异常问题
@@ -196,6 +235,49 @@ public class BidServiceImpl implements IBidService
         }
     }
 
+    private String ruleType(Live live) {
+        return Objects.nonNull(live) && Objects.nonNull(live.getLot()) ? live.getLot().getRuleType() : null;
+    }
+
+    private Long onceDelayTime(Live live) {
+        if (live instanceof TraditionLive && Objects.nonNull(((TraditionLive) live).getTraditionRule())) {
+            return ((TraditionLive) live).getTraditionRule().getOnceDelayTime();
+        }
+        return null;
+    }
+
+    private BigDecimal currentPrice(Live live) {
+        if (live instanceof TraditionLive) {
+            return ((TraditionLive) live).getCurrentPrice();
+        }
+        return null;
+    }
+
+    private BigDecimal currentStartPrice(Live live) {
+        if (live instanceof TraditionLive) {
+            return ((TraditionLive) live).getCurrentStartPrice();
+        }
+        return null;
+    }
+
+    private BigDecimal currentOnceAddPrice(Live live) {
+        if (live instanceof TraditionLive) {
+            return ((TraditionLive) live).getCurrentOnceAddPrice();
+        }
+        return null;
+    }
+
+//    private void publishChange(Live live, List<Bid> bidList) {
+//        try {
+//            if (Objects.nonNull(eventPublisher)) {
+//                eventPublisher.publishChangeEvent(new ChangeEvent(live, null, bidList));
+//            }
+//        } catch (Exception e) {
+//            log.error("publish addPrice change event error, lotId:{}",
+//                    Objects.nonNull(live) && Objects.nonNull(live.getLot()) ? live.getLot().getId() : null, e);
+//        }
+//    }
+
     private void insertCurrBid(BidVO bid, Long round) {
         bidMapper.clearCurrentBid(bid.getLotId());
         bid.setDelFlag(Constants.DEL_FLAG_NO_DELETE);