feat:fwd下单优化

This commit is contained in:
Zhujx
2025-09-30 15:54:52 +08:00
parent 387cbf4575
commit 876a0dbb81
8 changed files with 144 additions and 19 deletions

View File

@@ -3,4 +3,8 @@ package com.xiang.xservice.fwd.constants;
public class CodeConstants { public class CodeConstants {
public static final Integer SUCCESS = 10000; public static final Integer SUCCESS = 10000;
public static final Integer LIMIT = 47009; public static final Integer LIMIT = 47009;
public static final Integer TOKEN_EXPIRED = 11004;
public static final Integer SYSTEM_ERROR = 90008;
} }

View File

@@ -37,4 +37,9 @@ public class UrlConstants {
* 查询观影人列表 * 查询观影人列表
*/ */
public final static String PROJECT_AUDIENCE_MEMBER_INFO = BASE_URL + "/member/member/bearer/app/list"; public final static String PROJECT_AUDIENCE_MEMBER_INFO = BASE_URL + "/member/member/bearer/app/list";
/**
* 服务端时间
*/
public final static String PERFORMANCE_SERVER_TIME = BASE_URL + "/performance/app/project/serverTime";
} }

View File

@@ -21,6 +21,7 @@ import com.xiang.xservice.fwd.mapper.FwdUserConfigMapper;
import com.xiang.xservice.fwd.service.DingTalkScriptFWDService; import com.xiang.xservice.fwd.service.DingTalkScriptFWDService;
import com.xiang.xservice.fwd.service.IPerformService; import com.xiang.xservice.fwd.service.IPerformService;
import com.xiang.xservice.fwd.service.IPerformServiceHttp; import com.xiang.xservice.fwd.service.IPerformServiceHttp;
import com.xiang.xservice.fwd.utils.TimeSyncUtils;
import com.xiang.xservice.schedule.core.DynamicTaskScheduler; import com.xiang.xservice.schedule.core.DynamicTaskScheduler;
import com.xiang.xservice.schedule.entity.ScheduledTaskEntity; import com.xiang.xservice.schedule.entity.ScheduledTaskEntity;
import com.xiang.xservice.schedule.entity.TaskConfig; import com.xiang.xservice.schedule.entity.TaskConfig;
@@ -78,10 +79,11 @@ public class FwdImportantMsgJob {
for (ScheduledTaskEntity taskEntity : taskList) { for (ScheduledTaskEntity taskEntity : taskList) {
HashMap params = com.alibaba.fastjson2.JSON.parseObject(taskEntity.getParameters(), HashMap.class); HashMap params = com.alibaba.fastjson2.JSON.parseObject(taskEntity.getParameters(), HashMap.class);
FwdOrderTaskParam param = MapUtils.isEmpty(params) ? new FwdOrderTaskParam(null, taskEntity.getId()) : new FwdOrderTaskParam((Long) params.get("projectId"), taskEntity.getId()); FwdOrderTaskParam param = MapUtils.isEmpty(params) ? new FwdOrderTaskParam(null, taskEntity.getId()) : new FwdOrderTaskParam((Long) params.get("projectId"), taskEntity.getId());
LocalDateTime runTime = taskEntity.getRunTime().isBefore(LocalDateTime.now()) ? LocalDateTime.now().plusMinutes(1) : taskEntity.getRunTime(); LocalDateTime runTime = taskEntity.getRunTime().isBefore(TimeSyncUtils.now()) ? TimeSyncUtils.now() : taskEntity.getRunTime();
dynamicTaskScheduler.schedule( dynamicTaskScheduler.schedule(
new TaskConfig(taskEntity.getId(), taskEntity.getTaskName(), taskEntity.getTaskGroup(), runTime, params), new TaskConfig(taskEntity.getId(), taskEntity.getTaskName(), taskEntity.getTaskGroup(), runTime, params),
new TicketGrabTask(fwdUserConfigMapper, fwdAudienceConfigMapper, iPerformService, param, dynamicTaskSchedulerService) new TicketGrabTask(fwdUserConfigMapper, fwdAudienceConfigMapper, iPerformService, param, dynamicTaskSchedulerService),
TimeSyncUtils.now()
); );
} }
} }
@@ -95,7 +97,7 @@ public class FwdImportantMsgJob {
performConfigMapper.delPerforms(); performConfigMapper.delPerforms();
// 查询所有即将今天预售的演唱会信息 // 查询所有即将今天预售的演唱会信息
LocalDate now = LocalDate.now(); LocalDate now = TimeSyncUtils.now().toLocalDate();
List<FPerformProjectInfo> saleTodayData = performProjectInfoMapper.getPreSaleTodayData(now.atTime(0, 0, 0), now.atTime(23, 59, 59)); List<FPerformProjectInfo> saleTodayData = performProjectInfoMapper.getPreSaleTodayData(now.atTime(0, 0, 0), now.atTime(23, 59, 59));
if (CollectionUtils.isEmpty(saleTodayData)) { if (CollectionUtils.isEmpty(saleTodayData)) {
log.info("【芬玩岛】 今天:{}暂无预售的演唱会门票信息.", now); log.info("【芬玩岛】 今天:{}暂无预售的演唱会门票信息.", now);
@@ -124,7 +126,8 @@ public class FwdImportantMsgJob {
new TaskConfig(taskId, "芬玩岛演唱会抢票-【" + data.getProjectName() + "", TaskGroupEnum.SERVICE_FWD_SCHEDULE.getCode(), new TaskConfig(taskId, "芬玩岛演唱会抢票-【" + data.getProjectName() + "", TaskGroupEnum.SERVICE_FWD_SCHEDULE.getCode(),
runTime, params), runTime, params),
new TicketGrabTask(fwdUserConfigMapper, fwdAudienceConfigMapper, iPerformService, new TicketGrabTask(fwdUserConfigMapper, fwdAudienceConfigMapper, iPerformService,
new FwdOrderTaskParam(data.getProjectId(), taskId), dynamicTaskSchedulerService)); new FwdOrderTaskParam(data.getProjectId(), taskId), dynamicTaskSchedulerService),
TimeSyncUtils.now());
savaTask(data, taskId, params); savaTask(data, taskId, params);
} }
msg.append("请注意进行数据库配置的更改!"); msg.append("请注意进行数据库配置的更改!");

View File

@@ -0,0 +1,36 @@
package com.xiang.xservice.fwd.schedule;
import com.xiang.xservice.fwd.service.IPerformServiceHttp;
import com.xiang.xservice.fwd.utils.TimeSyncUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Objects;
/**
* @Author: xiang
* @Date: 2025-09-30 14:56
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class FwdTimeSyncJob {
private final IPerformServiceHttp performServiceHttp;
@Scheduled(fixedRate = 60_000) // 每分钟执行一次
public void syncTime() {
try {
// 调用对方接口
Long timeStamp = performServiceHttp.getServerTimeStamp();
if (Objects.equals(timeStamp,-1L)) {
log.info("请求服务器时间失败!");
return;
}
TimeSyncUtils.syncWithServer(timeStamp);
} catch (Exception e) {
log.error("同步时间失败", e);
}
}
}

View File

@@ -54,5 +54,11 @@ public interface IPerformServiceHttp {
*/ */
List<AudienceMemberInfo> getAudienceMemberInfo(String token); List<AudienceMemberInfo> getAudienceMemberInfo(String token);
/**
* http请求获取时间
* @return
*/
Long getServerTimeStamp();
} }

View File

@@ -26,6 +26,7 @@ import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Random;
@Service @Service
@Slf4j @Slf4j
@@ -100,6 +101,11 @@ public class PerformServiceHttpServiceImpl implements IPerformServiceHttp {
} }
return projectOrderCreateResp; return projectOrderCreateResp;
} }
if (Objects.nonNull(code) && Objects.equals(code, CodeConstants.LIMIT)) {
Integer waitTime = new Random().nextInt(10);
log.info("触发FWD限流机制等待:{}秒后重新发送。", waitTime);
return null;
}
return null; return null;
} }
@@ -170,6 +176,23 @@ public class PerformServiceHttpServiceImpl implements IPerformServiceHttp {
return Lists.newArrayList(); return Lists.newArrayList();
} }
@Override
public Long getServerTimeStamp() {
String respStr = HttpUtils.doGet(UrlConstants.PERFORMANCE_SERVER_TIME, buildFWDHeaders(null), null);
if (StringUtils.isBlank(respStr)) {
return -1L;
}
JSONObject jsonObject = JSON.parseObject(respStr);
if (Objects.nonNull(jsonObject)) {
Integer code = (Integer) jsonObject.get("code");
if (Objects.equals(code, CodeConstants.SUCCESS)) {
Long timestamp = (Long) jsonObject.get("data");
return timestamp;
}
}
return -1L;
}
private Map<String, String> buildFWDHeaders(String token) { private Map<String, String> buildFWDHeaders(String token) {
Map<String, String> headers = Maps.newHashMap(); Map<String, String> headers = Maps.newHashMap();
headers.put("Host", "api.livelab.com.cn"); headers.put("Host", "api.livelab.com.cn");

View File

@@ -19,6 +19,7 @@ import com.xiang.xservice.http.helper.HttpRequestHelper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -87,21 +88,7 @@ public class PerformServiceImpl implements IPerformService {
if (1 == fPerformSeatInfo.getSoldOut()) { if (1 == fPerformSeatInfo.getSoldOut()) {
continue; continue;
} }
ProjectOrderCreateReq projectOrderCreateReq = new ProjectOrderCreateReq(); ProjectOrderCreateReq projectOrderCreateReq = buildReq(projectId, frequentIds, fPerformSeatInfo);
projectOrderCreateReq.setDeliveryType(1);
projectOrderCreateReq.setContactName("朱吉祥");
projectOrderCreateReq.setContactPhone("15858717571");
projectOrderCreateReq.setPayment(fPerformSeatInfo.getPrice().multiply(BigDecimal.valueOf(frequentIds.size())).setScale(2));
projectOrderCreateReq.setTotalPrice(fPerformSeatInfo.getPrice().multiply(BigDecimal.valueOf(frequentIds.size())).setScale(2, BigDecimal.ROUND_HALF_UP));
projectOrderCreateReq.setPerformId(fPerformSeatInfo.getPerformId());
projectOrderCreateReq.setProjectId(projectId.toString());
projectOrderCreateReq.setPrivilegeCodeList(new ArrayList<>());
projectOrderCreateReq.setAudienceCount(frequentIds.size());
projectOrderCreateReq.setFrequentIds(frequentIds);
projectOrderCreateReq.setSeatPlanIds(Collections.singletonList(fPerformSeatInfo.getSeatPlanId()));
projectOrderCreateReq.setBlackBox("0");
projectOrderCreateReq.setCombineTicketVos(null);
projectOrderCreateReq.setOrdinaryTicketVos(null);
for (int i = 1; i <= 10; i++) { for (int i = 1; i <= 10; i++) {
ProjectOrderCreateResp projectOrder = httpRequestHelper.fetchWithRetry(() -> performServiceHttp.createProjectOrder(projectOrderCreateReq, availableUser.get(0).getToken()), "create-project-order"); ProjectOrderCreateResp projectOrder = httpRequestHelper.fetchWithRetry(() -> performServiceHttp.createProjectOrder(projectOrderCreateReq, availableUser.get(0).getToken()), "create-project-order");
if (Objects.nonNull(projectOrder)) { if (Objects.nonNull(projectOrder)) {
@@ -116,6 +103,26 @@ public class PerformServiceImpl implements IPerformService {
return Boolean.FALSE; return Boolean.FALSE;
} }
@NotNull
private static ProjectOrderCreateReq buildReq(Long projectId, List<Long> frequentIds, FPerformSeatInfo fPerformSeatInfo) {
ProjectOrderCreateReq projectOrderCreateReq = new ProjectOrderCreateReq();
projectOrderCreateReq.setDeliveryType(1);
projectOrderCreateReq.setContactName("朱吉祥");
projectOrderCreateReq.setContactPhone("15858717571");
projectOrderCreateReq.setPayment(fPerformSeatInfo.getPrice().multiply(BigDecimal.valueOf(frequentIds.size())).setScale(2));
projectOrderCreateReq.setTotalPrice(fPerformSeatInfo.getPrice().multiply(BigDecimal.valueOf(frequentIds.size())).setScale(2, BigDecimal.ROUND_HALF_UP));
projectOrderCreateReq.setPerformId(fPerformSeatInfo.getPerformId());
projectOrderCreateReq.setProjectId(projectId.toString());
projectOrderCreateReq.setPrivilegeCodeList(new ArrayList<>());
projectOrderCreateReq.setAudienceCount(frequentIds.size());
projectOrderCreateReq.setFrequentIds(frequentIds);
projectOrderCreateReq.setSeatPlanIds(Collections.singletonList(fPerformSeatInfo.getSeatPlanId()));
projectOrderCreateReq.setBlackBox("0");
projectOrderCreateReq.setCombineTicketVos(null);
projectOrderCreateReq.setOrdinaryTicketVos(null);
return projectOrderCreateReq;
}
@Override @Override
public List<FPerformConfig> getAvailablePerform() { public List<FPerformConfig> getAvailablePerform() {
return fwdPerformConfigMapper.getAvailablePerform(); return fwdPerformConfigMapper.getAvailablePerform();

View File

@@ -0,0 +1,41 @@
package com.xiang.xservice.fwd.utils;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
/**
* @Author: xiang
* @Date: 2025-09-30 14:58
*/
public class TimeSyncUtils {
private static volatile long offset = 0;
/**
* 初始化/更新偏移量
*/
public static void syncWithServer(long serverTime) {
long localTime = System.currentTimeMillis();
offset = serverTime - localTime;
}
/**
* 获取同步后的时间戳
* @return
*/
public static long currentTimeMillis() {
return System.currentTimeMillis() + offset;
}
/**
* 获取同步后的 LocalDateTime
* @return
*/
public static LocalDateTime now() {
return LocalDateTime.ofInstant(
Instant.ofEpochMilli(currentTimeMillis()),
ZoneId.systemDefault()
);
}
}