fix(shadow): respect queue phases and compress input evidence

This commit is contained in:
zgw
2026-09-08 11:23:50 +08:00
parent 414b3bf4a9
commit af8b5f1830
40 changed files with 1035 additions and 46 deletions

View File

@@ -39,12 +39,20 @@ public final class ShadowDispatchSnapshotAssembler {
private final long topologyVersion;
private final Function<EffectiveTopology, ShadowTrafficState> stateLoader;
private final Clock clock;
private final java.util.Set<String> safeWaitSites;
private final java.util.Set<String> safeYieldSites;
public ShadowDispatchSnapshotAssembler(
String warehouseCode,
long topologyVersion,
Function<EffectiveTopology, ShadowTrafficState> stateLoader,
Clock clock) {
this(warehouseCode, topologyVersion, stateLoader, clock, Collections.emptySet(), Collections.emptySet());
}
public ShadowDispatchSnapshotAssembler(String warehouseCode, long topologyVersion,
Function<EffectiveTopology, ShadowTrafficState> stateLoader, Clock clock,
java.util.Set<String> safeWaitSites, java.util.Set<String> safeYieldSites) {
this.warehouseCode = required(warehouseCode, "warehouseCode");
if (topologyVersion <= 0L) {
throw new IllegalArgumentException(
@@ -53,6 +61,8 @@ public final class ShadowDispatchSnapshotAssembler {
this.topologyVersion = topologyVersion;
this.stateLoader = Objects.requireNonNull(stateLoader, "stateLoader");
this.clock = Objects.requireNonNull(clock, "clock");
this.safeWaitSites = safeSites(safeWaitSites);
this.safeYieldSites = safeSites(safeYieldSites);
}
public DispatchSnapshot assemble(ShadowFactBatch batch) {
@@ -74,7 +84,8 @@ public final class ShadowDispatchSnapshotAssembler {
continue;
}
nodes.add(new TopologyNode(fact.getSiteId(), floor(fact.getZ()),
fact.getX(), fact.getY(), 1, false, false));
fact.getX(), fact.getY(), 1, safeWaitSites.contains(fact.getSiteId()),
safeYieldSites.contains(fact.getSiteId())));
String coordinate = coordinate(fact.getX(), fact.getY(), fact.getZ());
if (coordinates.put(coordinate, fact) != null) {
throw new IllegalArgumentException(
@@ -96,7 +107,26 @@ public final class ShadowDispatchSnapshotAssembler {
Collections.<ResourceDefinition>emptyList(),
Collections.<String>emptyList(),
Collections.<String>emptyList());
return new TopologyCompiler().compile(definition);
EffectiveTopology topology = new TopologyCompiler().compile(definition);
java.util.Set<String> configured = new java.util.LinkedHashSet<String>(safeWaitSites);
configured.addAll(safeYieldSites);
for (String id : configured) {
if (!topology.containsNode(id) || topology.neighbors(id).size() < 2) {
throw new IllegalArgumentException("INVALID_CONFIGURED_SAFE_SITE:" + id);
}
}
return topology;
}
public static java.util.Set<String> safeSites(java.util.Set<String> values) {
java.util.Set<String> normalized = new java.util.TreeSet<String>();
for (String value : Objects.requireNonNull(values, "safeSites")) {
String id = required(value, "safeSite");
if (!id.matches("[0-9]{1,6}") || Integer.parseInt(id) == 0)
throw new IllegalArgumentException("INVALID_CONFIGURED_SAFE_SITE:" + id);
normalized.add(id);
}
return Collections.unmodifiableSet(normalized);
}
private List<DispatchTask> tasks(ShadowFactBatch batch,
@@ -104,10 +134,10 @@ public final class ShadowDispatchSnapshotAssembler {
List<DispatchTask> tasks = new ArrayList<DispatchTask>();
Instant now = clock.instant();
for (ShadowQueueFact fact : batch.getQueues()) {
if (!ACTIVE_QUEUE.equals(fact.getTableName())) {
if (com.ruoyi.shadow.facts.ShadowQueueDispatchEligibility.observationReason(fact, batch) != null) {
continue;
}
String source = required(ShadowQueueEndpoints.start(fact, batch), "startSite");
String source = required(ShadowQueueEndpoints.dispatchStart(fact, batch), "startSite");
String destination = required(ShadowQueueEndpoints.end(fact, batch), "endSite");
if (!topology.containsNode(source)
|| !topology.containsNode(destination)) {
@@ -130,6 +160,10 @@ public final class ShadowDispatchSnapshotAssembler {
values.put("parentTaskId", parentTaskId);
values.put("phase", phase(required(fact.getTaskType(), "taskType")));
values.put("routeVersion", Long.toString(topologyVersion));
String boundVehicle = optional(fact.getAgvId());
if (boundVehicle != null && !"0".equals(boundVehicle)) {
values.put("shadowBoundVehicleId", boundVehicle);
}
values.put("taskNo", positiveNumber(parentTaskId, "taskNo"));
short taskType = parsedShort(required(fact.getDefault02(), "default02"),
"default02");