fix: EventCar 同车 Tick 串行并覆盖基类 Stop
上一拍未结束则跳过本拍,避免断网重试堆积;Stop 调用 base.Stop 并清空工作线程。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -8,6 +8,7 @@ using SimpleCore.PropType;
|
|||||||
using StandardScene;
|
using StandardScene;
|
||||||
using StandardScene.Scheduler.FassEvent;
|
using StandardScene.Scheduler.FassEvent;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -68,6 +69,9 @@ namespace StandardScene.Scheduler
|
|||||||
/// <summary>记录每辆车上一周期的 CurrentNode,用于 PrevNode 触发与地标变化时清除任务防重复标记。</summary>
|
/// <summary>记录每辆车上一周期的 CurrentNode,用于 PrevNode 触发与地标变化时清除任务防重复标记。</summary>
|
||||||
[JsonIgnore] private readonly Dictionary<int, string> _prevNodeByCarId = new Dictionary<int, string>();
|
[JsonIgnore] private readonly Dictionary<int, string> _prevNodeByCarId = new Dictionary<int, string>();
|
||||||
|
|
||||||
|
/// <summary>每车最多一个在飞 Tick,避免断网重试把 Task.Run 堆爆、同一车并发下发。</summary>
|
||||||
|
[JsonIgnore] private readonly ConcurrentDictionary<int, byte> _tickInFlight = new ConcurrentDictionary<int, byte>();
|
||||||
|
|
||||||
/// <summary>进程运行状态扩展字段。</summary>
|
/// <summary>进程运行状态扩展字段。</summary>
|
||||||
public class EventCarMissionStatus : MissionStatus
|
public class EventCarMissionStatus : MissionStatus
|
||||||
{
|
{
|
||||||
@@ -140,9 +144,9 @@ namespace StandardScene.Scheduler
|
|||||||
Diagnosis.Post($"FASS EventCar 配置已加载:{path},事件数={_eventCars.Count}", "FassEventCar", true);
|
Diagnosis.Post($"FASS EventCar 配置已加载:{path},事件数={_eventCars.Count}", "FassEventCar", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>停止轮询并等待工作线程结束(最多 2 秒)。</summary>
|
/// <summary>停止轮询并等待工作线程结束(最多 2 秒)。覆盖基类 Stop,避免全量重载后线程仍在对全场车下发。</summary>
|
||||||
[MethodMember(Name = "停止进程", Description = "停止 FASS 车辆事件轮询")]
|
[MethodMember(Name = "停止进程", Description = "停止 FASS 车辆事件轮询")]
|
||||||
public void Stop()
|
public override void Stop()
|
||||||
{
|
{
|
||||||
_started = false;
|
_started = false;
|
||||||
try
|
try
|
||||||
@@ -153,8 +157,10 @@ namespace StandardScene.Scheduler
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
status.status = "已停止";
|
_workerThread = null;
|
||||||
Diagnosis.Post("FASS车辆事件进程已停止", "FassEventCar", true);
|
Diagnosis.Post("FASS车辆事件进程已停止", "FassEventCar", true);
|
||||||
|
base.Stop();
|
||||||
|
status.status = "已停止";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -182,14 +188,18 @@ namespace StandardScene.Scheduler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 遍历所有 Car,构建快照并异步调用 Handler(与 FASS Task.Run 行为一致)。
|
/// 遍历所有 Car,构建快照后 Task.Run 处理:一车断网不堵其它车。
|
||||||
/// <para>
|
/// 同一车上一拍未结束则跳过本拍,禁止无界堆积。
|
||||||
/// 跳过 status 为空或 usage.refreshing=false 的车辆(未参与调度刷新的车不处理)。
|
|
||||||
/// 当地标变化时清除 <see cref="FassEventCarHandler.ActiveTaskTag"/>,允许在新地标重新触发事件。
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void ProcessAllCars()
|
private void ProcessAllCars()
|
||||||
{
|
{
|
||||||
|
var handler = _handler;
|
||||||
|
var eventCars = _eventCars;
|
||||||
|
if (handler == null || eventCars == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var car in SimpleLib.GetAllCars().OfType<Car>())
|
foreach (var car in SimpleLib.GetAllCars().OfType<Car>())
|
||||||
{
|
{
|
||||||
if (car.status == null)
|
if (car.status == null)
|
||||||
@@ -207,13 +217,37 @@ namespace StandardScene.Scheduler
|
|||||||
_prevNodeByCarId.TryGetValue(car.id, out var prevNode);
|
_prevNodeByCarId.TryGetValue(car.id, out var prevNode);
|
||||||
var snapshot = FassEventCarSnapshotFactory.Create(car, prevNode, FassEventCarSnapshotFactory.GetNextNodeCode(car));
|
var snapshot = FassEventCarSnapshotFactory.Create(car, prevNode, FassEventCarSnapshotFactory.GetNextNodeCode(car));
|
||||||
|
|
||||||
Task.Run(() => _handler.HandleCarTimerTick(car, snapshot, _eventCars));
|
|
||||||
|
|
||||||
if (!string.Equals(prevNode, currentNode, StringComparison.OrdinalIgnoreCase))
|
if (!string.Equals(prevNode, currentNode, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
_prevNodeByCarId[car.id] = currentNode;
|
_prevNodeByCarId[car.id] = currentNode;
|
||||||
ClearTaskTags(car);
|
ClearTaskTags(car);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_tickInFlight.TryAdd(car.id, 0))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var carId = car.id;
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_started)
|
||||||
|
handler.HandleCarTimerTick(car, snapshot, eventCars);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Diagnosis.Post(
|
||||||
|
$"FASS车辆事件处理异常 car={carId}:{ExceptionFormatter.FormatEx(ex)}",
|
||||||
|
"FassEventCar",
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_tickInFlight.TryRemove(carId, out _);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace StandardScene.Scheduler.FassEvent
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 单次 TimerTick 对一辆车的处理入口(通常在 Task.Run 中调用)。
|
/// 单次 TimerTick 对一辆车的处理入口(由 EventCarMission 按车 Task.Run,同车同时只跑一拍)。
|
||||||
/// 仅处理 TriggerEvent=TimerTick 的配置项。
|
/// 仅处理 TriggerEvent=TimerTick 的配置项。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void HandleCarTimerTick(Car car, FassEventCarSnapshot snapshot, IReadOnlyList<FassEventCarConfig> eventCars)
|
public void HandleCarTimerTick(Car car, FassEventCarSnapshot snapshot, IReadOnlyList<FassEventCarConfig> eventCars)
|
||||||
|
|||||||
Reference in New Issue
Block a user