using System.Diagnostics; using System.Text; using ConsoleApp2.Helpers; using ConsoleApp2.Helpers.Database; using ConsoleApp2.HostedServices.Abstractions; using ConsoleApp2.Options; using ConsoleApp2.Services; using ConsoleApp2.Services.ErrorRecorder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace ConsoleApp2.HostedServices; public class MainHostedService : BackgroundService { private Stopwatch? _stopwatch; private readonly IInputService _input; private readonly ITransformService _transform; private readonly IOutputService _output; private readonly ILogger _logger; private readonly ProcessContext _context; private readonly IOptions _databaseOptions; private readonly IOptions _tenantDbOptions; private readonly IConfiguration _config; public MainHostedService(IInputService input, ITransformService transform, IOutputService output, ILogger logger, IOptions tenantDbOptions, IOptions databaseOptions, IConfiguration config, ProcessContext context) { _input = input; _transform = transform; _output = output; _logger = logger; _tenantDbOptions = tenantDbOptions; _databaseOptions = databaseOptions; _config = config; _context = context; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _stopwatch = Stopwatch.StartNew(); var inputTask = ExecuteAndCatch( async () => await _input.ExecuteAsync(stoppingToken), "文件输入程序出现异常", stoppingToken); var transformTask = ExecuteAndCatch( async () => await _transform.ExecuteAsync(stoppingToken), "转换程序出现异常", stoppingToken); var outputTask = ExecuteAndCatch( async () => await _output.ExecuteAsync(stoppingToken), "输出程序出现异常", stoppingToken); await Task.WhenAll(inputTask, transformTask, outputTask); _stopwatch.Stop(); _logger.LogInformation("***** All tasks completed *****"); _logger.LogInformation("***** ElapseTime: {Time}", (_stopwatch.ElapsedMilliseconds / 1000f).ToString("F3")); await Task.Delay(5000, stoppingToken); if (!stoppingToken.IsCancellationRequested) { await ExportResultAsync(); _logger.LogInformation("The execution result export to {Path}", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Result-{ErrorRecorder.UID}.md")); if (_config["RestoreIndex"] is not null) await RestoreIndexAsync(); Environment.Exit(0); } else Environment.Exit(1); } private Task ExecuteAndCatch(Func func, string message, CancellationToken ct) { return Task.Run(async () => { try { await func(); } catch (Exception e) { _logger.LogCritical(e, "{Msg}\t{ErrMsg}", message, e.Message); _context.AddException(e); Environment.Exit(1); } }, ct); } /// /// 还原所有数据库的索引... /// /// /// private Task RestoreIndexAsync() { var databases = _tenantDbOptions.Value.DbList?.Keys ?? throw new ApplicationException("无法还原索引,因为分库配置中没有配置数据库"); var connStr = _databaseOptions.Value.ConnectionString ?? throw new ApplicationException("无法还原索引,因为没有配置数据库连接字符串"); var list = new List(); foreach(var db in databases) { var task = DatabaseHelper.NonQueryAsync(connStr + $";Database={db};", """ CREATE INDEX `idx_CompanyID` ON `machine` (`CompanyID`); CREATE INDEX `idx_companyid` ON `order` (`CompanyID`); CREATE INDEX `idx_CompanyID` ON `order_block_plan` (`CompanyID`); CREATE INDEX `idx_PlanID` ON `order_block_plan_item` (`PlanID`); CREATE INDEX `idx_orderno` ON `order_box_block` (`OrderNo`); CREATE INDEX `index_OrderNo` ON `order_data_block` (`OrderNo`); CREATE INDEX `index_OrderNo` ON `order_data_goods` (`OrderNo`); CREATE INDEX `index_OrderNo` ON `order_data_parts` (`OrderNo`); CREATE INDEX `index_ItemNo` ON `order_item` (`ItemNo`); CREATE INDEX `index_OrderNo` ON `order_item` (`OrderNo`); CREATE INDEX `index_PackageID` ON `order_item` (`PackageID`); CREATE INDEX `index_PlanID` ON `order_item` (`PlanID`); CREATE INDEX `idx_OrderNo` ON `order_module` (`OrderNo`); CREATE INDEX `index_OrderNo` ON `order_module_extra` (`OrderNo`); CREATE INDEX `index_OrderNo` ON `order_module_item` (`OrderNo`); CREATE INDEX `idx_OrderNo` ON `order_package` (`OrderNo`); CREATE INDEX `idx_PakageNo` ON `order_package` (`PakageNo`); CREATE INDEX `idx_PackageID` ON `order_package_item` (`PackageID`); CREATE INDEX `idx_companyid` ON `order_patch_detail` (`CompanyID`); CREATE INDEX `idx_OrderNo` ON `order_process` (`OrderNo`); CREATE INDEX `index_CompanyID` ON `order_process_schdule` (`CompanyID`); CREATE INDEX `IX_order_process_step_OrderProcessID` ON `order_process_step` (`OrderProcessID`); CREATE INDEX `idx_OrderProcessID` ON `order_process_step_item` (`OrderProcessID`); CREATE INDEX `idx_OrderProcessStepID` ON `order_process_step_item` (`OrderProcessStepID`); CREATE INDEX `idx_CompanyID` ON `order_scrap_board` (`CompanyID`); CREATE INDEX `idx_CompanyID` ON `process_group` (`CompanyID`); CREATE INDEX `idx_CompanyID` ON `process_info` (`CompanyID`); CREATE INDEX `index_CompanyID` ON `process_item_exp` (`CompanyID`); CREATE INDEX `idx_CompanyID` ON `process_schdule_capacity` (`CompanyID`); CREATE INDEX `idx_CompanyID` ON `process_step_efficiency` (`CompanyID`); CREATE INDEX `idx_CompanyID` ON `report_template` (`CompanyID`); CREATE INDEX `indx_OrderNo` ON `simple_package` (`OrderNo`); CREATE INDEX `idx_CompanyID` ON `simple_plan_order` (`CompanyID`); CREATE INDEX `idx_CompanyID` ON `sys_config` (`CompanyID`); CREATE INDEX `idx` ON `work_calendar` (`CompanyID`); CREATE INDEX `idx_CompanyID` ON `work_shift` (`CompanyID`); CREATE INDEX `IX_work_time_ShiftID` ON `work_time` (`ShiftID`); """); list.Add(task); } return Task.WhenAll(list); } private async Task ExportResultAsync() { var sb = new StringBuilder(); if (_context.HasException) sb.AppendLine("# Program Completed With Error"); else sb.AppendLine("# Program Completed Successfully"); sb.AppendLine("## Process Count"); var processCount = new[] { new { State = "Input", Count = _context.InputCount }, new { State = "Transform", Count = _context.TransformCount }, new { State = "Output", Count = _context.OutputCount } }; sb.AppendLine(processCount.ToMarkdownTable()); sb.AppendLine("\n---\n"); sb.AppendLine("## Table Output Progress"); var tableOutputProgress = _context.TableProgress.Select(pair => new { Table = pair.Key, Count = pair.Value }); sb.AppendLine(tableOutputProgress.ToMarkdownTable()); sb.AppendLine("\n---\n"); sb.AppendLine("## Result"); var elapsedTime = (_stopwatch!.ElapsedMilliseconds / 1000f); var result = new[] { new { Field = "ElapsedTime", Value = elapsedTime.ToString("F2") }, new { Field = "Average Output Speed", Value = (_context.OutputCount / elapsedTime).ToString("F2") + "records/s" } }; sb.AppendLine(result.ToMarkdownTable()); await File.WriteAllTextAsync(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Result-{ErrorRecorder.UID}.md"), sb.ToString()); } }