| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- using System.Text.Json;
- using Admin.NET.Plugin.ApprovalFlow.Service;
- using Furion.Schedule;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Logging;
- namespace Admin.NET.Plugin.ApprovalFlow;
- /// <summary>
- /// 审批超时自动处理作业 — 每 5 分钟扫描一次超时的待办任务
- /// </summary>
- [JobDetail("job_flow_timeout", Description = "审批超时自动处理",
- GroupName = "default", Concurrent = false)]
- [Period(300000, TriggerId = "trigger_flow_timeout", Description = "每5分钟执行")]
- public class FlowTimeoutJob : IJob
- {
- private readonly IServiceScopeFactory _scopeFactory;
- private readonly ILogger _logger;
- public FlowTimeoutJob(IServiceScopeFactory scopeFactory, ILoggerFactory loggerFactory)
- {
- _scopeFactory = scopeFactory;
- _logger = loggerFactory.CreateLogger("FlowTimeoutJob");
- }
- public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
- {
- using var scope = _scopeFactory.CreateScope();
- var db = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>().CopyNew();
- var engine = scope.ServiceProvider.GetRequiredService<FlowEngineService>();
- var pendingTasks = await db.Queryable<ApprovalFlowTask>()
- .InnerJoin<ApprovalFlowInstance>((t, i) => t.InstanceId == i.Id)
- .Where((t, i) => t.Status == FlowTaskStatusEnum.Pending
- && i.Status == FlowInstanceStatusEnum.Running)
- .Select((t, i) => new
- {
- TaskId = t.Id,
- TaskCreatedAt = t.CreateTime,
- NodeId = t.NodeId,
- FlowJsonSnapshot = i.FlowJsonSnapshot,
- })
- .ToListAsync();
- var now = DateTime.Now;
- var processed = 0;
- foreach (var item in pendingTasks)
- {
- if (stoppingToken.IsCancellationRequested) break;
- try
- {
- if (string.IsNullOrWhiteSpace(item.FlowJsonSnapshot)) continue;
- var flowData = JsonSerializer.Deserialize<ApprovalFlowItem>(item.FlowJsonSnapshot);
- var node = flowData?.Nodes?.FirstOrDefault(n => n.Id == item.NodeId);
- var props = node?.Properties;
- if (props?.TimeoutHours == null || props.TimeoutHours <= 0) continue;
- if (string.IsNullOrWhiteSpace(props.TimeoutAction)) continue;
- var deadline = item.TaskCreatedAt.AddHours(props.TimeoutHours.Value);
- if (now < deadline) continue;
- if (props.TimeoutAction == "Notify")
- {
- var alreadyNotified = await db.Queryable<ApprovalFlowLog>()
- .AnyAsync(log => log.TaskId == item.TaskId
- && log.Action == FlowLogActionEnum.AutoTimeout);
- if (alreadyNotified) continue;
- }
- await engine.HandleTimeoutTask(item.TaskId);
- processed++;
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "处理超时任务 {TaskId} 失败", item.TaskId);
- }
- }
- if (processed > 0)
- _logger.LogInformation("FlowTimeoutJob 本轮处理了 {Count} 个超时任务", processed);
- }
- }
|