using Cowain.Base.DBContext; using Cowain.Base.Services; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Plugin.Cowain.Driver.Abstractions; using Plugin.Cowain.Wcs.IServices; using Plugin.Cowain.Wcs.Models.Dto; using Plugin.Cowain.Wcs.Models.Enum; namespace Plugin.Cowain.Wcs.Services; public class FindFlowTaskService : BaseService, IFindFlowTaskService { private class ProcessFlowInfo { public ProcessFlowInfo(ProcessDto process, ProcessFlowDto flow) { Process = process; Flow = flow; } public ProcessDto Process { get; set; } public ProcessFlowDto Flow { get; set; } } private static SemaphoreSlim semaphore = new SemaphoreSlim(1); private IDeviceMonitor _deviceMonitor; private IProcessService _processService; private IServiceScopeFactory _scopeFactory; private readonly ILogger _logger; public FindFlowTaskService(IDbContextFactory dbContextFactory, IServiceScopeFactory scopeFactory, IDeviceMonitor deviceMonitor, IProcessService processService, ILogger logger) : base(dbContextFactory) { _deviceMonitor = deviceMonitor; _processService = processService; _scopeFactory = scopeFactory; _logger = logger; } /// /// 根据工站列表和流程工艺列表,构建所有可执行的候选任务 /// private List BuildCandidateTasks(List stations, List processAndFlows) { var candidateTasks = new List(); foreach (var item in processAndFlows) { var flow = item.Flow; var process = item.Process; // 第一段工站匹配 var fromStation1 = stations.FirstOrDefault(s => s.ProcessName == process.Name && s.Id == flow.FromStationId1 && s.Status == flow.FromStatus1); var toStation1 = stations.FirstOrDefault(s => s.ProcessName == process.Name && s.Id == flow.ToStationId1 && s.Status == flow.ToStatus1); if (fromStation1 == null || toStation1 == null) continue; // 第二段工站匹配(如有) bool secondMatched = true; if (!(flow.FromStationId2 == 0 && flow.ToStationId2 == 0)) { var fromStation2 = stations.FirstOrDefault(s => s.ProcessName == process.Name && s.Id == flow.FromStationId2 && s.Status == flow.FromStatus2); var toStation2 = stations.FirstOrDefault(s => s.ProcessName == process.Name && s.Id == flow.ToStationId2 && s.Status == flow.ToStatus2); if (fromStation2 == null || toStation2 == null) secondMatched = false; } if (secondMatched) { candidateTasks.Add(new TaskDataDto { ProcessId = process.Id, ProcessName = process.Name, Priority = flow.Priority, FromStationId1 = flow.FromStationId1, ToStationId1 = flow.ToStationId1, FromStatus1 = flow.FromStatus1, ToStatus1 = flow.ToStatus1, FromStationId2 = flow.FromStationId2, ToStationId2 = flow.ToStationId2, FromStatus2 = flow.FromStatus2, ToStatus2 = flow.ToStatus2, ExecuteAction = 0, IsFinished = false, Action = flow.Action, }); } } return candidateTasks; } /// /// 延时查询任务(非阻塞方式) /// private async Task DelayedQueryAsync(TaskDataDto originalTask) { try { await Task.Delay(10000).ConfigureAwait(false); _logger.LogInformation($"延时10秒后重新查询任务,原任务:{JsonConvert.SerializeObject(originalTask)}"); // 使用新的作用域创建独立的DbContext using var scope = _scopeFactory.CreateScope(); var tempService = scope.ServiceProvider.GetRequiredService(); await tempService.FindTaskAsync(originalTask); } catch (Exception ex) { _logger.LogError(ex, "延时查询任务失败"); } } /// /// 保存任务并执行 /// private async Task SaveAndExecuteTask(TaskDataDto task) { using var dbContext = _dbContextFactory.CreateDbContext(); var taskSet = dbContext.GetDbSet(); await taskSet.AddAsync(task); var saveCount = await dbContext.SaveChangesAsync(); if (saveCount > 0) { _logger.LogInformation($"找到并添加任务:{JsonConvert.SerializeObject(task)}"); var getJson = await _processService.GetJsonData(task.ProcessId); if (getJson.IsSuccess) { var taskJsonParam = _deviceMonitor.GetActionParam(getJson.Data!.PlcName!, getJson.Data!.Address!); if (taskJsonParam.IsSuccess) { using var scope = _scopeFactory.CreateScope(); var taskService = scope.ServiceProvider.GetRequiredService(); var execute = await taskService.ExecuteAsync(taskJsonParam.Data, RgvUpdateSourceEnum.First); } } else { _logger.LogError(getJson.ErrorMessage); } } else { _logger.LogError("任务添加失败"); } } public async Task FindTaskAsync(TaskDataDto? taskData = null) { try { await semaphore.WaitAsync(); using var dbContext = _dbContextFactory.CreateDbContext(); var taskSet = dbContext.GetDbSet(); var unfinishedTask = await taskSet.AsNoTracking().FirstOrDefaultAsync(t => !t.IsFinished); if (unfinishedTask != null) { _logger.LogInformation($"已有未完成的任务,任务ID:{unfinishedTask.Id},任务内容:{JsonConvert.SerializeObject(unfinishedTask)}"); return; } var rgvSet = dbContext.GetDbSet(); var processSet = dbContext.GetDbSet(); var flowSet = dbContext.GetDbSet(); var stationSet = dbContext.GetDbSet(); // 只查可用工站 var enabledStations = await stationSet.AsNoTracking().Where(s => s.Enable && s.NextStationId <= 0).ToListAsync(); // 组合所有流程和工艺 var query = from flow in flowSet join process in processSet on flow.ProcessId equals process.Id select new ProcessFlowInfo(process, flow); var processAndFlows = await query.ToListAsync(); // 查找候选任务 var candidateTasks = BuildCandidateTasks(enabledStations, processAndFlows); // 取优先级最高的 //var findTask = candidateTasks // .OrderByDescending(x => x.Priority) // .FirstOrDefault(); // 取优先级最高的,如果有多条则按距离(RGV->From1 + From1->To1)最小选取 TaskDataDto? findTask = null; if (candidateTasks != null && candidateTasks.Count > 0) { var maxPriority = candidateTasks.Max(x => x.Priority); var topCandidates = candidateTasks.Where(x => x.Priority == maxPriority).ToList(); if (topCandidates.Count == 1) { //只有一条最高优先级任务,直接选取 findTask = topCandidates[0]; _logger.LogInformation($"最优任务只有一条,任务内容:{JsonConvert.SerializeObject(findTask)}"); } else { //优先级最高的任务大于1个,尝试获取当前RGV位置 var rgv = await rgvSet.AsNoTracking().FirstOrDefaultAsync(); if (rgv == null) { // 无RGV位置时,退回到取第一条 findTask = topCandidates[0]; _logger.LogInformation($"rgv位置获取失败,使用默认最优任务,任务内容:{JsonConvert.SerializeObject(findTask)}"); } else { double bestDistance = double.MaxValue; foreach (var cand in topCandidates) { //遍历优先级最高的任务,计算距离 var fromStation = enabledStations.FirstOrDefault(s => s.Id == cand.FromStationId1); var toStation = enabledStations.FirstOrDefault(s => s.Id == cand.ToStationId1); if (fromStation == null || toStation == null) continue; // 计算:|RGV.X - From.X| + |From.X - To.X| var distance = Math.Abs((double)rgv.LayOutX - (double)fromStation.LayOutX) + Math.Abs((double)fromStation.LayOutX - (double)toStation.LayOutX); if (distance < bestDistance) { bestDistance = distance; findTask = cand; } } // 如果遍历未找到合法候选(异常情况),退回到第一条 if (findTask == null) { findTask = topCandidates[0]; } else { _logger.LogInformation($"最优任务找到,距离:{bestDistance},任务内容:{JsonConvert.SerializeObject(findTask)}"); } } } } // 如果taskData不为空,说明是通过延时查询触发的 if (taskData != null) { if (findTask == null) { _logger.LogInformation($"延时查询后,没有找到新任务,保存原任务"); await SaveAndExecuteTask(taskData); } else { _logger.LogInformation($"通过延时查询触发的查询,原任务:{JsonConvert.SerializeObject(taskData)}"); // 如果查询到第二段还是0且第一段相同,保存这个task if (findTask.FromStationId2 == 0 && findTask.ToStationId2 == 0) { _logger.LogInformation($"延时查询后,还是只有单段任务,保存原任务"); await SaveAndExecuteTask(taskData); } // 如果查询到第二段不是0的任务,保存新任务 else if (findTask.FromStationId2 != 0 || findTask.ToStationId2 != 0) { _logger.LogInformation($"延时查询后,找到更好的两段任务,保存新任务"); await SaveAndExecuteTask(findTask); } else { _logger.LogInformation($"延时查询后,没有找到更好的任务,不保存"); } } } else { if (findTask == null) { _logger.LogInformation($"没有需要执行的任务"); return; } // 首次查询 if (findTask.FromStationId2 == 0 && findTask.ToStationId2 == 0) { // 任务的第二段是0,启动非阻塞的延时查询 _logger.LogInformation($"当前任务第二段为0,需要重新查询,原任务:{JsonConvert.SerializeObject(findTask)}"); // 使用Task.Run启动非阻塞的延时查询,不等待其完成 _ = Task.Run(async () => await DelayedQueryAsync(findTask)); } else { // 直接保存任务 await SaveAndExecuteTask(findTask); } } } catch (Exception ex) { _logger.LogError(ex, "查找任务失败"); } finally { semaphore.Release(); } } }