优化订单状态更新和统计服务
1. 订单详情为 null 且已部分卖出的订单超时清理 - 新增 PARTIAL_SOLD_CLEANUP_WINDOW_MS 常量(1小时) - 超过1小时无法获取详情的已部分卖出订单自动清理 - 避免无效订单长期占用数据库空间 2. 优化买入订单分组排序逻辑 - 按最近买入订单时间排序,提升用户体验 - 修复日志中的错误描述(卖出订单列表) 3. 代码格式化优化
This commit is contained in:
+21
-13
@@ -611,22 +611,22 @@ class CopyTradingStatisticsService(
|
|||||||
|
|
||||||
// 4. 转换为分组数据并计算统计信息
|
// 4. 转换为分组数据并计算统计信息
|
||||||
val marketIds = groups.keys.toList()
|
val marketIds = groups.keys.toList()
|
||||||
|
|
||||||
val list = marketIds.map { marketId ->
|
val list = marketIds.map { marketId ->
|
||||||
val marketOrders = groups[marketId] ?: mutableListOf()
|
val marketOrders = groups[marketId] ?: mutableListOf()
|
||||||
|
|
||||||
// 计算统计信息
|
// 计算统计信息
|
||||||
val count = marketOrders.size.toLong()
|
val count = marketOrders.size.toLong()
|
||||||
val totalAmount = marketOrders.sumOf { order ->
|
val totalAmount = marketOrders.sumOf { order ->
|
||||||
order.quantity.toSafeBigDecimal().multi(order.price)
|
order.quantity.toSafeBigDecimal().multi(order.price)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算订单状态统计
|
// 计算订单状态统计
|
||||||
val fullyMatchedCount = marketOrders.count { it.status == "fully_matched" }
|
val fullyMatchedCount = marketOrders.count { it.status == "fully_matched" }
|
||||||
val partiallyMatchedCount = marketOrders.count { it.status == "partially_matched" }
|
val partiallyMatchedCount = marketOrders.count { it.status == "partially_matched" }
|
||||||
val filledCount = marketOrders.count { it.status == "filled" }
|
val filledCount = marketOrders.count { it.status == "filled" }
|
||||||
val fullyMatched = fullyMatchedCount == marketOrders.size
|
val fullyMatched = fullyMatchedCount == marketOrders.size
|
||||||
|
|
||||||
val stats = MarketOrderStats(
|
val stats = MarketOrderStats(
|
||||||
count = count,
|
count = count,
|
||||||
totalAmount = totalAmount.toString(),
|
totalAmount = totalAmount.toString(),
|
||||||
@@ -636,10 +636,10 @@ class CopyTradingStatisticsService(
|
|||||||
partiallyMatchedCount = partiallyMatchedCount.toLong(),
|
partiallyMatchedCount = partiallyMatchedCount.toLong(),
|
||||||
filledCount = filledCount.toLong()
|
filledCount = filledCount.toLong()
|
||||||
)
|
)
|
||||||
|
|
||||||
// 排序(按创建时间倒序)
|
// 排序(按创建时间倒序)
|
||||||
marketOrders.sortByDescending { it.createdAt }
|
marketOrders.sortByDescending { it.createdAt }
|
||||||
|
|
||||||
// 转换为 DTO
|
// 转换为 DTO
|
||||||
val orderDtos = marketOrders.map { order ->
|
val orderDtos = marketOrders.map { order ->
|
||||||
val amount = order.quantity.toSafeBigDecimal().multi(order.price)
|
val amount = order.quantity.toSafeBigDecimal().multi(order.price)
|
||||||
@@ -662,7 +662,7 @@ class CopyTradingStatisticsService(
|
|||||||
createdAt = order.createdAt
|
createdAt = order.createdAt
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
MarketOrderGroup(
|
MarketOrderGroup(
|
||||||
marketId = marketId,
|
marketId = marketId,
|
||||||
marketTitle = markets[marketId]?.title,
|
marketTitle = markets[marketId]?.title,
|
||||||
@@ -672,27 +672,35 @@ class CopyTradingStatisticsService(
|
|||||||
stats = stats,
|
stats = stats,
|
||||||
orders = orderDtos as List<Any>
|
orders = orderDtos as List<Any>
|
||||||
)
|
)
|
||||||
}.sortedByDescending { it.stats.count }
|
}.sortedByDescending { group ->
|
||||||
|
// 找出该市场最近的买入订单时间
|
||||||
|
group.orders.mapNotNull { order ->
|
||||||
|
when (order) {
|
||||||
|
is BuyOrderInfo -> order.createdAt
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}.maxOrNull() ?: 0L
|
||||||
|
}
|
||||||
|
|
||||||
// 5. 分页
|
// 5. 分页
|
||||||
val page = (request.page ?: 1)
|
val page = (request.page ?: 1)
|
||||||
val limit = request.limit ?: 20
|
val limit = request.limit ?: 20
|
||||||
val total = list.size.toLong()
|
val total = list.size.toLong()
|
||||||
|
|
||||||
val start = (page - 1) * limit
|
val start = (page - 1) * limit
|
||||||
val end = minOf(start + limit, list.size)
|
val end = minOf(start + limit, list.size)
|
||||||
val pagedList = if (start < list.size) list.subList(start, end) else emptyList()
|
val pagedList = if (start < list.size) list.subList(start, end) else emptyList()
|
||||||
|
|
||||||
val response = MarketGroupedOrdersResponse(
|
val response = MarketGroupedOrdersResponse(
|
||||||
list = pagedList,
|
list = pagedList,
|
||||||
total = total,
|
total = total,
|
||||||
page = page,
|
page = page,
|
||||||
limit = limit
|
limit = limit
|
||||||
)
|
)
|
||||||
|
|
||||||
Result.success(response)
|
Result.success(response)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger.error("获取按市场分组的买入订单列表失败: copyTradingId=${request.copyTradingId}", e)
|
logger.error("获取按市场分组的卖出订单列表失败: copyTradingId=${request.copyTradingId}", e)
|
||||||
Result.failure(e)
|
Result.failure(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-8
@@ -49,6 +49,9 @@ class OrderStatusUpdateService(
|
|||||||
// 订单详情为 null 的重试时间窗口(1分钟)
|
// 订单详情为 null 的重试时间窗口(1分钟)
|
||||||
private val ORDER_NULL_RETRY_WINDOW_MS = 60000L
|
private val ORDER_NULL_RETRY_WINDOW_MS = 60000L
|
||||||
|
|
||||||
|
// 订单详情为 null 但已部分卖出的清理时间窗口(1小时)
|
||||||
|
private val PARTIAL_SOLD_CLEANUP_WINDOW_MS = 3600000L
|
||||||
|
|
||||||
@EventListener(ApplicationReadyEvent::class)
|
@EventListener(ApplicationReadyEvent::class)
|
||||||
fun onApplicationReady() {
|
fun onApplicationReady() {
|
||||||
logger.info("订单状态更新服务已启动,将每5秒轮询一次")
|
logger.info("订单状态更新服务已启动,将每5秒轮询一次")
|
||||||
@@ -234,10 +237,25 @@ class OrderStatusUpdateService(
|
|||||||
// 检查订单是否已部分卖出,如果已部分卖出则保留订单用于统计
|
// 检查订单是否已部分卖出,如果已部分卖出则保留订单用于统计
|
||||||
val hasMatchedDetails = sellMatchDetailRepository.findByTrackingId(order.id!!).isNotEmpty()
|
val hasMatchedDetails = sellMatchDetailRepository.findByTrackingId(order.id!!).isNotEmpty()
|
||||||
if (hasMatchedDetails || order.matchedQuantity > BigDecimal.ZERO) {
|
if (hasMatchedDetails || order.matchedQuantity > BigDecimal.ZERO) {
|
||||||
logger.debug("订单详情为 null 但已部分卖出,保留订单用于统计: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, matchedQuantity=${order.matchedQuantity}")
|
// 检查是否超过清理时间窗口(1小时)
|
||||||
// 清除缓存,下次重新检测
|
val orderAge = currentTime - order.createdAt
|
||||||
orderNullDetectionTime.remove(order.buyOrderId)
|
if (orderAge >= PARTIAL_SOLD_CLEANUP_WINDOW_MS) {
|
||||||
continue
|
logger.warn("订单详情为 null 且已部分卖出,但超过清理时间窗口,删除本地订单: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, matchedQuantity=${order.matchedQuantity}, 已等待=${orderAge / 1000}s")
|
||||||
|
try {
|
||||||
|
copyOrderTrackingRepository.deleteById(order.id!!)
|
||||||
|
logger.info("已删除本地订单(超时清理): orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}")
|
||||||
|
// 清除缓存
|
||||||
|
orderNullDetectionTime.remove(order.buyOrderId)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error("删除本地订单失败: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, error=${e.message}", e)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
logger.debug("订单详情为 null 但已部分卖出,保留订单用于统计: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, matchedQuantity=${order.matchedQuantity}, 已等待=${orderAge / 1000}s")
|
||||||
|
// 清除缓存,下次重新检测
|
||||||
|
orderNullDetectionTime.remove(order.buyOrderId)
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否超过重试时间窗口
|
// 检查是否超过重试时间窗口
|
||||||
@@ -645,10 +663,25 @@ class OrderStatusUpdateService(
|
|||||||
// 检查订单是否已部分卖出,如果已部分卖出则保留订单用于统计
|
// 检查订单是否已部分卖出,如果已部分卖出则保留订单用于统计
|
||||||
val hasMatchedDetails = sellMatchDetailRepository.findByTrackingId(order.id!!).isNotEmpty()
|
val hasMatchedDetails = sellMatchDetailRepository.findByTrackingId(order.id!!).isNotEmpty()
|
||||||
if (hasMatchedDetails || order.matchedQuantity > BigDecimal.ZERO) {
|
if (hasMatchedDetails || order.matchedQuantity > BigDecimal.ZERO) {
|
||||||
logger.debug("订单详情为 null 但已部分卖出,保留订单用于统计: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, matchedQuantity=${order.matchedQuantity}")
|
// 检查是否超过清理时间窗口(1小时)
|
||||||
// 清除缓存,下次重新检测
|
val orderAge = currentTime - order.createdAt
|
||||||
orderNullDetectionTime.remove(order.buyOrderId)
|
if (orderAge >= PARTIAL_SOLD_CLEANUP_WINDOW_MS) {
|
||||||
continue
|
logger.warn("订单详情为 null 且已部分卖出,但超过清理时间窗口,删除本地订单: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, matchedQuantity=${order.matchedQuantity}, 已等待=${orderAge / 1000}s")
|
||||||
|
try {
|
||||||
|
copyOrderTrackingRepository.deleteById(order.id!!)
|
||||||
|
logger.info("已删除本地订单(超时清理): orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}")
|
||||||
|
// 清除缓存
|
||||||
|
orderNullDetectionTime.remove(order.buyOrderId)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error("删除本地订单失败: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, error=${e.message}", e)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
logger.debug("订单详情为 null 但已部分卖出,保留订单用于统计: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, matchedQuantity=${order.matchedQuantity}, 已等待=${orderAge / 1000}s")
|
||||||
|
// 清除缓存,下次重新检测
|
||||||
|
orderNullDetectionTime.remove(order.buyOrderId)
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否超过重试时间窗口
|
// 检查是否超过重试时间窗口
|
||||||
|
|||||||
Reference in New Issue
Block a user