2024-01-29 09:29:16 +08:00
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using ConsoleApp2.Helpers;
|
|
|
|
|
using ConsoleApp2.Helpers.Database;
|
|
|
|
|
using ConsoleApp2.HostedServices.Abstractions;
|
2024-01-18 14:36:36 +08:00
|
|
|
|
using ConsoleApp2.Options;
|
2024-01-12 16:50:37 +08:00
|
|
|
|
using ConsoleApp2.Services;
|
2024-01-29 09:29:16 +08:00
|
|
|
|
using ConsoleApp2.Services.ErrorRecorder;
|
|
|
|
|
using Microsoft.Extensions.Configuration;
|
2024-01-04 09:00:44 +08:00
|
|
|
|
using Microsoft.Extensions.Hosting;
|
2024-01-12 16:50:37 +08:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
2024-01-29 09:29:16 +08:00
|
|
|
|
using Microsoft.Extensions.Options;
|
|
|
|
|
|
2024-01-04 09:00:44 +08:00
|
|
|
|
namespace ConsoleApp2.HostedServices;
|
|
|
|
|
|
|
|
|
|
public class MainHostedService : BackgroundService
|
|
|
|
|
{
|
2024-01-29 09:29:16 +08:00
|
|
|
|
private Stopwatch? _stopwatch;
|
2024-01-04 09:00:44 +08:00
|
|
|
|
private readonly IInputService _input;
|
|
|
|
|
private readonly ITransformService _transform;
|
|
|
|
|
private readonly IOutputService _output;
|
2024-01-29 09:29:16 +08:00
|
|
|
|
private readonly ILogger _logger;
|
2024-01-12 16:50:37 +08:00
|
|
|
|
private readonly ProcessContext _context;
|
2024-01-29 09:29:16 +08:00
|
|
|
|
|
|
|
|
|
private readonly IOptions<DatabaseOutputOptions> _databaseOptions;
|
|
|
|
|
private readonly IOptions<TenantDbOptions> _tenantDbOptions;
|
|
|
|
|
private readonly IConfiguration _config;
|
2024-01-04 09:00:44 +08:00
|
|
|
|
|
2024-01-29 09:29:16 +08:00
|
|
|
|
public MainHostedService(IInputService input,
|
|
|
|
|
ITransformService transform,
|
|
|
|
|
IOutputService output,
|
|
|
|
|
ILogger<MainHostedService> logger,
|
|
|
|
|
IOptions<TenantDbOptions> tenantDbOptions,
|
|
|
|
|
IOptions<DatabaseOutputOptions> databaseOptions,
|
|
|
|
|
IConfiguration config,
|
|
|
|
|
ProcessContext context)
|
2024-01-04 09:00:44 +08:00
|
|
|
|
{
|
|
|
|
|
_input = input;
|
|
|
|
|
_transform = transform;
|
|
|
|
|
_output = output;
|
2024-01-29 09:29:16 +08:00
|
|
|
|
_logger = logger;
|
|
|
|
|
_tenantDbOptions = tenantDbOptions;
|
|
|
|
|
_databaseOptions = databaseOptions;
|
|
|
|
|
_config = config;
|
2024-01-12 16:50:37 +08:00
|
|
|
|
_context = context;
|
2024-01-04 09:00:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
|
|
|
{
|
2024-01-29 09:29:16 +08:00
|
|
|
|
_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)
|
2024-01-12 16:50:37 +08:00
|
|
|
|
{
|
2024-01-29 09:29:16 +08:00
|
|
|
|
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<Task> func, string message, CancellationToken ct)
|
|
|
|
|
{
|
|
|
|
|
return Task.Run(async () =>
|
|
|
|
|
{
|
|
|
|
|
try
|
2024-01-12 16:50:37 +08:00
|
|
|
|
{
|
2024-01-29 09:29:16 +08:00
|
|
|
|
await func();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
2024-01-12 16:50:37 +08:00
|
|
|
|
{
|
2024-01-29 09:29:16 +08:00
|
|
|
|
_logger.LogCritical(e, "{Msg}\t{ErrMsg}", message, e.Message);
|
|
|
|
|
_context.AddException(e);
|
|
|
|
|
Environment.Exit(1);
|
|
|
|
|
}
|
|
|
|
|
}, ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 还原所有数据库的索引...
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
/// <exception cref="ApplicationException"></exception>
|
|
|
|
|
private Task RestoreIndexAsync()
|
|
|
|
|
{
|
|
|
|
|
var databases = _tenantDbOptions.Value.DbList?.Keys
|
|
|
|
|
?? throw new ApplicationException("无法还原索引,因为分库配置中没有配置数据库");
|
|
|
|
|
var connStr = _databaseOptions.Value.ConnectionString
|
|
|
|
|
?? throw new ApplicationException("无法还原索引,因为没有配置数据库连接字符串");
|
|
|
|
|
var list = new List<Task>();
|
|
|
|
|
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`);
|
2024-01-12 16:50:37 +08:00
|
|
|
|
|
2024-01-29 09:29:16 +08:00
|
|
|
|
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[]
|
2024-01-18 14:36:36 +08:00
|
|
|
|
{
|
2024-01-29 09:29:16 +08:00
|
|
|
|
new { State = "Input", Count = _context.InputCount },
|
|
|
|
|
new { State = "Transform", Count = _context.TransformCount },
|
|
|
|
|
new { State = "Output", Count = _context.OutputCount }
|
2024-01-18 14:36:36 +08:00
|
|
|
|
};
|
2024-01-29 09:29:16 +08:00
|
|
|
|
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[]
|
2024-01-18 14:36:36 +08:00
|
|
|
|
{
|
2024-01-29 09:29:16 +08:00
|
|
|
|
new { Field = "ElapsedTime", Value = elapsedTime.ToString("F2") },
|
|
|
|
|
new
|
|
|
|
|
{
|
|
|
|
|
Field = "Average Output Speed",
|
|
|
|
|
Value = (_context.OutputCount / elapsedTime).ToString("F2") + "records/s"
|
|
|
|
|
}
|
2024-01-18 14:36:36 +08:00
|
|
|
|
};
|
2024-01-29 09:29:16 +08:00
|
|
|
|
sb.AppendLine(result.ToMarkdownTable());
|
|
|
|
|
await File.WriteAllTextAsync(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Result-{ErrorRecorder.UID}.md"),
|
|
|
|
|
sb.ToString());
|
2024-01-04 09:00:44 +08:00
|
|
|
|
}
|
|
|
|
|
}
|