From f83364ec7a0bdb6daa4b087e37f09feb5495e984 Mon Sep 17 00:00:00 2001
From: haoliang <821644@qq.com>
Date: Fri, 8 May 2026 19:27:37 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=A7=E9=87=8F=E7=BB=9F?=
=?UTF-8?q?=E8=AE=A13=E4=B8=AABug=EF=BC=9Amanual=5Freset/program=5Fchange?=
=?UTF-8?q?=E4=BA=A7=E9=87=8F=E4=B8=A2=E5=A4=B1=E3=80=81=E6=97=A5=E7=BB=88?=
=?UTF-8?q?=E6=B1=87=E6=80=BB=E5=A4=B1=E8=B4=A5=E4=B8=8D=E9=87=8D=E8=AF=95?=
=?UTF-8?q?=E3=80=81=E6=97=A5=E5=BF=97=E5=BD=92=E6=A1=A3=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=E9=94=81=E5=86=B2=E7=AA=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bug#1(核心): ProductionTracker.Track()中manual_reset和program_change段结账时
endPartCount传入了复位后/新程序的值而非结账段最后已知值,导致50个manual_reset
段产量全部为0,program_change段产量偏差
Bug#2: _lastSummaryDate在DailySummaryJob.Execute()执行前就设置,若汇总失败则
永久无法重试。修改为Execute返回bool,成功后设置;时间窗口扩大到±2分钟
Bug#3: log4net RollingFileAppender默认排他锁与LogArchiveJob的File.WriteAllText冲突
导致IOException。改用Date滚动+MinimalLock模式,删除手写LogArchiveJob
---
src/CncCollector/Core/CollectorEngine.cs | 25 ++--
src/CncCollector/Core/DailySummaryJob.cs | 5 +-
src/CncCollector/Core/ProductionTracker.cs | 6 +-
src/CncCollector/Jobs/LogArchiveJob.cs | 151 ---------------------
src/CncCollector/log4net.config | 18 +--
5 files changed, 33 insertions(+), 172 deletions(-)
delete mode 100644 src/CncCollector/Jobs/LogArchiveJob.cs
diff --git a/src/CncCollector/Core/CollectorEngine.cs b/src/CncCollector/Core/CollectorEngine.cs
index d936fd2..6f2a2ed 100644
--- a/src/CncCollector/Core/CollectorEngine.cs
+++ b/src/CncCollector/Core/CollectorEngine.cs
@@ -30,7 +30,6 @@ namespace CncCollector.Core
private Timer _dailySummaryTimer;
private Timer _logCleanupTimer;
private LogCleanupJob _logCleanupJob;
- private LogArchiveJob _logArchiveJob;
private DateTime _startTime;
private long _totalSuccess;
private long _totalFail;
@@ -60,8 +59,6 @@ namespace CncCollector.Core
_dailySummary = new DailySummaryJob(config.BusinessConnection);
// 初始化分析引擎(与业务库和日志库同源,后续按需调整)
_analysisEngine = new AnalysisEngine(config.BusinessConnection, config.LogConnection);
- // 初始化日志归档任务(保留30天)
- _logArchiveJob = new LogArchiveJob(30);
}
///
@@ -184,10 +181,11 @@ namespace CncCollector.Core
/// 手动执行日终汇总(指定日期)
///
/// 要汇总的日期
- public void RunDailySummary(DateTime summaryDate)
+ /// true=汇总成功
+ public bool RunDailySummary(DateTime summaryDate)
{
_log.Info($"手动触发日终汇总(日期={summaryDate:yyyy-MM-dd})");
- _dailySummary.Execute(summaryDate);
+ return _dailySummary.Execute(summaryDate);
}
///
@@ -331,17 +329,22 @@ namespace CncCollector.Core
var now = DateTime.Now;
var targetTime = new DateTime(now.Year, now.Month, now.Day, summaryTime.Hours, summaryTime.Minutes, 0);
- // 检查是否到了汇总时间(±1分钟内)
- if (Math.Abs((now - targetTime).TotalMinutes) <= 1)
+ // 检查是否到了汇总时间(±2分钟内,比之前±1分钟更宽松,防止定时器偏移导致错过窗口)
+ if (Math.Abs((now - targetTime).TotalMinutes) <= 2)
{
// 汇总昨天的数据
DateTime summaryDate = now.Date.AddDays(-1);
if (_lastSummaryDate != summaryDate)
{
- _lastSummaryDate = summaryDate;
- _dailySummary.Execute(summaryDate);
- // 同步执行日志归档:把前一天的日志移到日期子目录
- _logArchiveJob.Execute();
+ // 修复:只在汇总成功后设置 _lastSummaryDate,失败时允许重试
+ if (_dailySummary.Execute(summaryDate))
+ {
+ _lastSummaryDate = summaryDate;
+ }
+ else
+ {
+ _log.Warn($"日终汇总失败(日期={summaryDate:yyyy-MM-dd}),将在下次检查时重试");
+ }
}
}
}
diff --git a/src/CncCollector/Core/DailySummaryJob.cs b/src/CncCollector/Core/DailySummaryJob.cs
index c32277e..8ddcc9a 100644
--- a/src/CncCollector/Core/DailySummaryJob.cs
+++ b/src/CncCollector/Core/DailySummaryJob.cs
@@ -31,7 +31,8 @@ namespace CncCollector.Core
/// 执行日终汇总,汇总指定日期的产量数据
///
/// 要汇总的日期(通常为昨天)
- public void Execute(DateTime summaryDate)
+ /// true=汇总成功,false=汇总失败(可重试)
+ public bool Execute(DateTime summaryDate)
{
_log.Info($"========== 日终汇总开始(日期={summaryDate:yyyy-MM-dd}) ==========");
var sw = System.Diagnostics.Stopwatch.StartNew();
@@ -124,10 +125,12 @@ namespace CncCollector.Core
sw.Stop();
_log.Info($"========== 日终汇总完成(日期={summaryDate:yyyy-MM-dd}, 耗时={sw.ElapsedMilliseconds}ms) ==========");
+ return true;
}
catch (Exception ex)
{
_log.Error($"日终汇总失败(日期={summaryDate:yyyy-MM-dd})", ex);
+ return false;
}
}
}
diff --git a/src/CncCollector/Core/ProductionTracker.cs b/src/CncCollector/Core/ProductionTracker.cs
index ed0fd7f..2f3f5fa 100644
--- a/src/CncCollector/Core/ProductionTracker.cs
+++ b/src/CncCollector/Core/ProductionTracker.cs
@@ -83,9 +83,13 @@ namespace CncCollector.Core
}
// 结账当前活跃段
+ // 修复:使用结账前最后已知的零件数(lastPartCount),而非当前观测值(partCount)
+ // 当 manual_reset 时 partCount 是复位后的值(如0),当 program_change 时 partCount 是新程序的值
+ // 正确的 endPartCount 应该是结账段最后观测到的最大计数值
if (needClose)
{
- CloseActiveSegment(machineId, partCount, closeReason, collectTime);
+ var closingEndCount = hasLast ? lastState.Item2 : partCount;
+ CloseActiveSegment(machineId, closingEndCount, closeReason, collectTime);
}
// 确保有活跃段
diff --git a/src/CncCollector/Jobs/LogArchiveJob.cs b/src/CncCollector/Jobs/LogArchiveJob.cs
deleted file mode 100644
index 3ed10e0..0000000
--- a/src/CncCollector/Jobs/LogArchiveJob.cs
+++ /dev/null
@@ -1,151 +0,0 @@
-using System;
-using System.IO;
-using log4net;
-
-namespace CncCollector.Jobs
-{
- ///
- /// 日志文件归档任务。
- /// 每天凌晨将前一天的日志文件移动到按日期命名的子目录中。
- /// 目录结构示例:
- /// logs\collector.log ← 当前在写的运行日志
- /// logs\collector_error.log ← 当前在写的错误日志
- /// logs\2026-05-07\collector.log
- /// logs\2026-05-07\collector_error.log
- /// logs\2026-05-06\collector.log
- /// logs\2026-05-06\collector_error.log
- /// 保留天数外的旧目录自动清理。
- ///
- public class LogArchiveJob
- {
- private static readonly ILog _log = LogManager.GetLogger(typeof(LogArchiveJob));
-
- ///
- /// 日志保留天数
- ///
- private readonly int _retainDays;
-
- ///
- /// 日志根目录(相对于BaseDirectory)
- ///
- private readonly string _logsDir;
-
- public LogArchiveJob(int retainDays = 30)
- {
- _retainDays = retainDays;
- _logsDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
- }
-
- ///
- /// 执行归档:把当前日志文件复制到昨天的日期目录,然后截断当前文件。
- /// 应在每天凌晨00:00左右调用。
- ///
- public void Execute()
- {
- try
- {
- if (!Directory.Exists(_logsDir))
- {
- return;
- }
-
- var yesterday = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd");
- var archiveDir = Path.Combine(_logsDir, yesterday);
-
- // 归档每个日志文件
- ArchiveLogFile("collector.log", archiveDir);
- ArchiveLogFile("collector_error.log", archiveDir);
-
- // 清理过期目录
- CleanupOldDirectories();
-
- _log.Info($"日志归档完成({yesterday})");
- }
- catch (Exception ex)
- {
- _log.Error("日志归档失败", ex);
- }
- }
-
- ///
- /// 归档单个日志文件到日期目录
- ///
- private void ArchiveLogFile(string fileName, string archiveDir)
- {
- var sourceFile = Path.Combine(_logsDir, fileName);
- if (!File.Exists(sourceFile))
- {
- return;
- }
-
- var fileInfo = new FileInfo(sourceFile);
-
- // 文件为空或太新(最后写入在1小时内)则跳过
- // 避免归档正在活跃写入的当天日志
- if (fileInfo.Length == 0)
- {
- return;
- }
-
- // 创建日期目录
- if (!Directory.Exists(archiveDir))
- {
- Directory.CreateDirectory(archiveDir);
- }
-
- var destFile = Path.Combine(archiveDir, fileName);
-
- // 如果目标已存在,追加序号
- if (File.Exists(destFile))
- {
- var seq = 1;
- var baseName = Path.GetFileNameWithoutExtension(fileName);
- var ext = Path.GetExtension(fileName);
- do
- {
- destFile = Path.Combine(archiveDir, $"{baseName}_{seq}{ext}");
- seq++;
- } while (File.Exists(destFile));
- }
-
- // 复制到日期目录(不是移动,因为log4net还持有文件句柄)
- File.Copy(sourceFile, destFile);
-
- // 截断当前日志文件(清空内容,但不删除文件,保持log4net文件句柄有效)
- File.WriteAllText(sourceFile, string.Empty);
-
- _log.Info($"已归档 {fileName} → {archiveDir}({fileInfo.Length} 字节)");
- }
-
- ///
- /// 清理超过保留天数的日期目录
- ///
- private void CleanupOldDirectories()
- {
- if (!Directory.Exists(_logsDir))
- {
- return;
- }
-
- var cutoff = DateTime.Now.AddDays(-_retainDays).ToString("yyyy-MM-dd");
-
- foreach (var dir in Directory.GetDirectories(_logsDir))
- {
- var dirName = Path.GetFileName(dir);
- // 日期目录格式:yyyy-MM-dd
- if (dirName.Length == 10 && dirName.Contains("-") && dirName.CompareTo(cutoff) < 0)
- {
- try
- {
- Directory.Delete(dir, true);
- _log.Info($"已清理过期日志目录:{dirName}");
- }
- catch (Exception ex)
- {
- _log.Warn($"清理过期日志目录失败:{dirName}", ex);
- }
- }
- }
- }
- }
-}
diff --git a/src/CncCollector/log4net.config b/src/CncCollector/log4net.config
index 93e4afa..3412939 100644
--- a/src/CncCollector/log4net.config
+++ b/src/CncCollector/log4net.config
@@ -7,27 +7,29 @@
-
+
-
-
-
+
+
+
+
-
+
-
-
-
+
+
+
+