提交更新

This commit is contained in:
super
2026-06-08 18:31:55 +08:00
parent 98e0e54309
commit 967eedcad7
7 changed files with 394 additions and 98 deletions
@@ -1,6 +1,8 @@
package com.nanri.aiimage.modules.pricetrack.model.entity;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -24,6 +26,7 @@ public class PriceTrackLoopRunEntity {
private String asinFilesJson;
private String countryCodesJson;
private String shopsJson;
@TableField(value = "active_task_id", updateStrategy = FieldStrategy.ALWAYS)
private Long activeTaskId;
private Boolean stopRequested;
private String errorMessage;
@@ -108,7 +108,7 @@ public class PriceTrackLoopRunService {
}
int shopIndex = Math.max(0, entity.getCurrentShopIndex() == null ? 0 : entity.getCurrentShopIndex());
if (shopIndex >= items.size()) {
advanceAfterSuccessfulRound(entity, items.size());
advanceAfterSuccessfulRound(entity);
if (isTerminal(entity.getStatus())) {
PriceTrackLoopRunDispatchVo vo = new PriceTrackLoopRunDispatchVo();
vo.setLoopRun(toVo(entity));
@@ -175,6 +175,8 @@ public class PriceTrackLoopRunService {
entity.setActiveTaskId(childTaskId);
entity.setUpdatedAt(LocalDateTime.now());
loopRunMapper.updateById(entity);
log.info("[price-track-loop] child bound loopRunId={} childTaskId={} roundIndex={} shopIndex={}",
loopRunId, childTaskId, roundIndex, shopIndex);
}
@Transactional
@@ -182,12 +184,7 @@ public class PriceTrackLoopRunService {
if (childTaskId == null || childTaskId <= 0) {
return;
}
List<PriceTrackLoopRunEntity> loops = loopRunMapper.selectList(new LambdaQueryWrapper<PriceTrackLoopRunEntity>()
.eq(PriceTrackLoopRunEntity::getActiveTaskId, childTaskId)
.last("limit 5"));
for (PriceTrackLoopRunEntity entity : loops) {
handleChildFinished(entity, childTaskId, false);
}
forEachLoopForChildTask(childTaskId, entity -> handleChildFinished(entity, childTaskId, false));
}
@Transactional
@@ -229,16 +226,22 @@ public class PriceTrackLoopRunService {
if (!belongsToLoop(task, entity.getId())) {
throw new BusinessException("子任务不属于当前循环");
}
ChildTaskContext ctx = parseChildTaskContext(task);
if (ctx == null) {
log.warn("[price-track-loop] child context missing loopRunId={} childTaskId={}", entity.getId(), childTaskId);
return;
}
boolean stateMatchesChild = ctx.roundIndex().equals(entity.getCurrentRound())
&& ctx.shopIndex().equals(entity.getCurrentShopIndex());
if (!stateMatchesChild && entity.getActiveTaskId() != null && entity.getActiveTaskId().equals(childTaskId)) {
log.warn("[price-track-loop] child context drift detected loopRunId={} childTaskId={} loopRound={} loopShopIndex={} childRound={} childShopIndex={}",
entity.getId(), childTaskId, entity.getCurrentRound(), entity.getCurrentShopIndex(), ctx.roundIndex(), ctx.shopIndex());
}
if (entity.getActiveTaskId() != null && !entity.getActiveTaskId().equals(childTaskId)) {
return;
}
if (entity.getActiveTaskId() == null) {
ChildTaskContext ctx = parseChildTaskContext(task);
if (ctx == null
|| !ctx.roundIndex().equals(entity.getCurrentRound())
|| !ctx.shopIndex().equals(entity.getCurrentShopIndex())) {
return;
}
if (entity.getActiveTaskId() == null && !stateMatchesChild) {
return;
}
entity.setActiveTaskId(null);
entity.setUpdatedAt(LocalDateTime.now());
@@ -249,6 +252,8 @@ public class PriceTrackLoopRunService {
: task.getErrorMessage());
entity.setFinishedAt(LocalDateTime.now());
loopRunMapper.updateById(entity);
log.warn("[price-track-loop] child finished as failed loopRunId={} childTaskId={} roundIndex={} shopIndex={} error={}",
entity.getId(), childTaskId, entity.getCurrentRound(), entity.getCurrentShopIndex(), entity.getErrorMessage());
return;
}
List<PriceTrackMatchShopsVo.PriceTrackShopQueueItem> items = parseShops(entity);
@@ -263,13 +268,23 @@ public class PriceTrackLoopRunService {
markStopped(entity, null);
return;
}
int nextShopIndex = (entity.getCurrentShopIndex() == null ? 0 : entity.getCurrentShopIndex()) + 1;
int currentRound = Math.max(1, ctx.roundIndex());
int currentShopIndex = Math.max(0, ctx.shopIndex());
int nextShopIndex = currentShopIndex + 1;
if (nextShopIndex < items.size()) {
entity.setStatus(STATUS_RUNNING);
entity.setErrorMessage(null);
entity.setFinishedAt(null);
entity.setCurrentRound(currentRound);
entity.setCurrentShopIndex(nextShopIndex);
loopRunMapper.updateById(entity);
log.info("[price-track-loop] child finished advanced shop loopRunId={} childTaskId={} nextRound={} nextShopIndex={}",
entity.getId(), childTaskId, currentRound, nextShopIndex);
return;
}
advanceAfterSuccessfulRound(entity, items.size());
advanceAfterSuccessfulRound(entity, currentRound);
log.info("[price-track-loop] child finished advanced round loopRunId={} childTaskId={} status={} currentRound={} currentShopIndex={} activeTaskId={}",
entity.getId(), childTaskId, entity.getStatus(), entity.getCurrentRound(), entity.getCurrentShopIndex(), entity.getActiveTaskId());
}
private void reconcileWithTerminalChild(PriceTrackLoopRunEntity entity) {
@@ -281,26 +296,37 @@ public class PriceTrackLoopRunService {
}
}
private void advanceAfterSuccessfulRound(PriceTrackLoopRunEntity entity, int shopCount) {
private void advanceAfterSuccessfulRound(PriceTrackLoopRunEntity entity) {
int currentRound = entity.getCurrentRound() == null ? 1 : Math.max(1, entity.getCurrentRound());
advanceAfterSuccessfulRound(entity, currentRound);
}
private void advanceAfterSuccessfulRound(PriceTrackLoopRunEntity entity, int completedRound) {
if (Boolean.TRUE.equals(entity.getStopRequested())) {
markStopped(entity, null);
return;
}
int normalizedCompletedRound = Math.max(1, completedRound);
if (EXECUTION_MODE_FINITE.equals(entity.getExecutionMode())) {
int targetRounds = entity.getTargetRounds() == null ? 1 : Math.max(1, entity.getTargetRounds());
int currentRound = entity.getCurrentRound() == null ? 1 : Math.max(1, entity.getCurrentRound());
if (currentRound >= targetRounds) {
if (normalizedCompletedRound >= targetRounds) {
entity.setStatus(STATUS_SUCCESS);
entity.setCurrentRound(normalizedCompletedRound);
entity.setCurrentShopIndex(0);
entity.setFinishedAt(LocalDateTime.now());
} else {
entity.setCurrentRound(currentRound + 1);
entity.setStatus(STATUS_RUNNING);
entity.setCurrentRound(normalizedCompletedRound + 1);
entity.setCurrentShopIndex(0);
entity.setFinishedAt(null);
}
} else {
int currentRound = entity.getCurrentRound() == null ? 1 : Math.max(1, entity.getCurrentRound());
entity.setCurrentRound(currentRound + 1);
entity.setStatus(STATUS_RUNNING);
entity.setCurrentRound(normalizedCompletedRound + 1);
entity.setCurrentShopIndex(0);
entity.setFinishedAt(null);
}
entity.setErrorMessage(null);
entity.setActiveTaskId(null);
entity.setUpdatedAt(LocalDateTime.now());
loopRunMapper.updateById(entity);
@@ -320,23 +346,51 @@ public class PriceTrackLoopRunService {
return task != null && isTerminal(task.getStatus());
}
private void forEachLoopForChildTask(Long childTaskId, java.util.function.Consumer<PriceTrackLoopRunEntity> consumer) {
Map<Long, PriceTrackLoopRunEntity> loopMap = new LinkedHashMap<>();
List<PriceTrackLoopRunEntity> activeLoops = loopRunMapper.selectList(new LambdaQueryWrapper<PriceTrackLoopRunEntity>()
.eq(PriceTrackLoopRunEntity::getActiveTaskId, childTaskId)
.last("limit 5"));
for (PriceTrackLoopRunEntity entity : activeLoops) {
if (entity != null && entity.getId() != null) {
loopMap.put(entity.getId(), entity);
}
}
FileTaskEntity task = fileTaskMapper.selectById(childTaskId);
Long loopRunId = parseLoopRunId(task);
if (loopRunId != null && !loopMap.containsKey(loopRunId)) {
PriceTrackLoopRunEntity loop = loopRunMapper.selectById(loopRunId);
if (loop != null) {
loopMap.put(loopRunId, loop);
}
}
for (PriceTrackLoopRunEntity entity : loopMap.values()) {
consumer.accept(entity);
}
}
private boolean belongsToLoop(FileTaskEntity task, Long loopRunId) {
Long childLoopRunId = parseLoopRunId(task);
return childLoopRunId != null && loopRunId.equals(childLoopRunId);
}
private Long parseLoopRunId(FileTaskEntity task) {
if (task == null || task.getRequestJson() == null || task.getRequestJson().isBlank()) {
return false;
return null;
}
try {
Map<String, Object> payload = objectMapper.readValue(task.getRequestJson(), new TypeReference<Map<String, Object>>() {});
Object raw = payload.get("loopRunId");
if (raw instanceof Number number) {
return loopRunId.equals(number.longValue());
return number.longValue();
}
if (raw instanceof String text && !text.isBlank()) {
return loopRunId.equals(Long.parseLong(text));
return Long.parseLong(text);
}
return false;
return null;
} catch (Exception ex) {
log.warn("[price-track-loop] parse child loopRunId failed taskId={} msg={}", task.getId(), ex.getMessage());
return false;
return null;
}
}