package com.zy.core.network.fake;
|
|
import com.zy.asrs.domain.vo.FakeTaskTraceEventVo;
|
import com.zy.asrs.domain.vo.FakeTaskTraceVo;
|
import org.springframework.stereotype.Component;
|
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.Comparator;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.concurrent.ConcurrentHashMap;
|
|
@Component
|
public class FakeTaskTraceRegistry {
|
|
private static final int MAX_EVENT_COUNT = 200;
|
private static final long TERMINAL_KEEP_MS = 3000L;
|
|
private final Map<Integer, TraceTaskState> taskStateMap = new ConcurrentHashMap<Integer, TraceTaskState>();
|
|
public void record(Integer taskNo, String threadImpl, String status, Integer startStationId,
|
Integer currentStationId, Integer finalTargetStationId, Integer blockedStationId,
|
List<Integer> stitchedPathStationIds, List<Integer> passedStationIds, List<Integer> pendingStationIds,
|
List<Integer> latestAppendedPath, String eventType, String message, Map<String, Object> details,
|
boolean terminal) {
|
if (taskNo == null || taskNo <= 0) {
|
return;
|
}
|
|
cleanupExpired();
|
TraceTaskState taskState = taskStateMap.computeIfAbsent(taskNo, TraceTaskState::new);
|
taskState.apply(threadImpl, status, startStationId, currentStationId, finalTargetStationId, blockedStationId,
|
stitchedPathStationIds, passedStationIds, pendingStationIds, latestAppendedPath, eventType, message,
|
details, terminal);
|
}
|
|
public List<FakeTaskTraceVo> listActiveTraces() {
|
cleanupExpired();
|
List<FakeTaskTraceVo> result = new ArrayList<FakeTaskTraceVo>();
|
for (TraceTaskState taskState : taskStateMap.values()) {
|
result.add(taskState.toVo());
|
}
|
Collections.sort(result, new Comparator<FakeTaskTraceVo>() {
|
@Override
|
public int compare(FakeTaskTraceVo o1, FakeTaskTraceVo o2) {
|
long v1 = o1.getUpdatedAt() == null ? 0L : o1.getUpdatedAt();
|
long v2 = o2.getUpdatedAt() == null ? 0L : o2.getUpdatedAt();
|
return Long.compare(v2, v1);
|
}
|
});
|
return result;
|
}
|
|
private void cleanupExpired() {
|
long now = System.currentTimeMillis();
|
for (Map.Entry<Integer, TraceTaskState> entry : taskStateMap.entrySet()) {
|
TraceTaskState state = entry.getValue();
|
if (state != null && state.shouldRemove(now)) {
|
taskStateMap.remove(entry.getKey(), state);
|
}
|
}
|
}
|
|
private static List<Integer> copyIntegerList(List<Integer> source) {
|
List<Integer> result = new ArrayList<Integer>();
|
if (source == null) {
|
return result;
|
}
|
for (Integer item : source) {
|
if (item != null) {
|
result.add(item);
|
}
|
}
|
return result;
|
}
|
|
private static Map<String, Object> copyDetails(Map<String, Object> source) {
|
Map<String, Object> result = new LinkedHashMap<String, Object>();
|
if (source == null || source.isEmpty()) {
|
return result;
|
}
|
for (Map.Entry<String, Object> entry : source.entrySet()) {
|
Object value = entry.getValue();
|
if (value instanceof List) {
|
result.put(entry.getKey(), new ArrayList<Object>((List<?>) value));
|
} else if (value instanceof Map) {
|
result.put(entry.getKey(), new LinkedHashMap<Object, Object>((Map<?, ?>) value));
|
} else {
|
result.put(entry.getKey(), value);
|
}
|
}
|
return result;
|
}
|
|
private static class TraceTaskState {
|
|
private final Integer taskNo;
|
private String threadImpl;
|
private String status = "WAITING";
|
private Integer startStationId;
|
private Integer currentStationId;
|
private Integer finalTargetStationId;
|
private Integer blockedStationId;
|
private List<Integer> stitchedPathStationIds = new ArrayList<Integer>();
|
private List<Integer> passedStationIds = new ArrayList<Integer>();
|
private List<Integer> pendingStationIds = new ArrayList<Integer>();
|
private List<Integer> latestAppendedPath = new ArrayList<Integer>();
|
private final List<FakeTaskTraceEventVo> events = new ArrayList<FakeTaskTraceEventVo>();
|
private Long updatedAt = System.currentTimeMillis();
|
private Long terminalExpireAt;
|
|
private TraceTaskState(Integer taskNo) {
|
this.taskNo = taskNo;
|
}
|
|
private synchronized void apply(String threadImpl, String status, Integer startStationId,
|
Integer currentStationId, Integer finalTargetStationId, Integer blockedStationId,
|
List<Integer> stitchedPathStationIds, List<Integer> passedStationIds, List<Integer> pendingStationIds,
|
List<Integer> latestAppendedPath, String eventType, String message, Map<String, Object> details,
|
boolean terminal) {
|
this.threadImpl = threadImpl;
|
this.status = status == null ? "WAITING" : status;
|
this.startStationId = startStationId;
|
this.currentStationId = currentStationId;
|
this.finalTargetStationId = finalTargetStationId;
|
this.blockedStationId = blockedStationId;
|
this.stitchedPathStationIds = copyIntegerList(stitchedPathStationIds);
|
this.passedStationIds = copyIntegerList(passedStationIds);
|
this.pendingStationIds = copyIntegerList(pendingStationIds);
|
this.latestAppendedPath = copyIntegerList(latestAppendedPath);
|
long now = System.currentTimeMillis();
|
this.updatedAt = now;
|
|
if (eventType != null) {
|
FakeTaskTraceEventVo event = new FakeTaskTraceEventVo();
|
event.setTimestamp(now);
|
event.setEventType(eventType);
|
event.setMessage(message);
|
event.setStatus(this.status);
|
event.setCurrentStationId(this.currentStationId);
|
event.setTargetStationId(this.finalTargetStationId);
|
event.setDetails(copyDetails(details));
|
this.events.add(event);
|
if (this.events.size() > MAX_EVENT_COUNT) {
|
this.events.remove(0);
|
}
|
}
|
|
this.terminalExpireAt = terminal ? now + TERMINAL_KEEP_MS : null;
|
}
|
|
private synchronized boolean shouldRemove(long now) {
|
return terminalExpireAt != null && terminalExpireAt <= now;
|
}
|
|
private synchronized FakeTaskTraceVo toVo() {
|
FakeTaskTraceVo vo = new FakeTaskTraceVo();
|
vo.setTaskNo(taskNo);
|
vo.setThreadImpl(threadImpl);
|
vo.setStatus(status);
|
vo.setStartStationId(startStationId);
|
vo.setCurrentStationId(currentStationId);
|
vo.setFinalTargetStationId(finalTargetStationId);
|
vo.setBlockedStationId(blockedStationId);
|
vo.setStitchedPathStationIds(copyIntegerList(stitchedPathStationIds));
|
vo.setPassedStationIds(copyIntegerList(passedStationIds));
|
vo.setPendingStationIds(copyIntegerList(pendingStationIds));
|
vo.setLatestAppendedPath(copyIntegerList(latestAppendedPath));
|
vo.setUpdatedAt(updatedAt);
|
vo.setEvents(new ArrayList<FakeTaskTraceEventVo>(events));
|
return vo;
|
}
|
}
|
}
|