瀏覽代碼

Worker 额外日志、迁移 IsGenericInstanceOf

龙腾猫跃 3 月之前
父節點
當前提交
fe9fc04c20
共有 3 個文件被更改,包括 41 次插入 和 11 次删除
  1. 15 0
      Shared/Extensions/GeneralExtension.cs
  2. 4 1
      Shared/General/Logger.cs
  3. 22 10
      Shared/General/Workers/RedoableWorker.cs

+ 15 - 0
Shared/Extensions/GeneralExtension.cs

@@ -0,0 +1,15 @@
+namespace MeloongCore.Extensions;
+public static class GeneralExtension {
+
+    /// <summary>
+    /// 判断对象是否为指定泛型类型的实例。
+    /// </summary>
+    public static bool IsGenericInstanceOf(this object? instance, Type genericTypeDefinition) {
+        if (instance is null) return false;
+        for (var type = instance.GetType(); type is not null; type = type.BaseType) {
+            if (type.IsGenericType && type.GetGenericTypeDefinition() == genericTypeDefinition) return true;
+        }
+        return false;
+    }
+
+}

+ 4 - 1
Shared/General/Logger.cs

@@ -219,7 +219,10 @@ public class BaseLogger {
             .Join("\r\n");
             .Join("\r\n");
     }
     }
     public static string GetLogPrefix(LogLevel level, string filePath)
     public static string GetLogPrefix(LogLevel level, string filePath)
-        => $"{DateTime.Now:HH':'mm':'ss'.'fff} {level.ToString().First()} {(Thread.CurrentThread.Name is null ? "" : $"<{Thread.CurrentThread.ManagedThreadId} · {Thread.CurrentThread.Name}> ")}[{PathUtils.GetLastPart(filePath).BeforeFirst(".")}] ";
+        => $"{DateTime.Now:HH':'mm':'ss'.'fff} {level.ToString().First()} {
+            (Thread.CurrentThread.Name is not null ? $"<{Thread.CurrentThread.ManagedThreadId} · {Thread.CurrentThread.Name}> " : 
+            (Thread.CurrentThread.IsThreadPoolThread ? "<Async> " : ""))}[{
+            PathUtils.GetLastPart(filePath).BeforeFirst(".")}] ";
 
 
     /// <summary>
     /// <summary>
     /// 执行 <see cref="LogBehavior"/>。
     /// 执行 <see cref="LogBehavior"/>。

+ 22 - 10
Shared/General/Workers/RedoableWorker.cs

@@ -33,12 +33,12 @@ public interface IWorker {
     ProgressProvider Progress { get; }
     ProgressProvider Progress { get; }
 }
 }
 
 
-// TODO: 现在的可观测性不佳,考虑增加调用方信息以及自身名称等,输出到日志,例如 CallerArgumentExpression
 /// <summary>
 /// <summary>
 /// 可合并和重启的工作器。
 /// 可合并和重启的工作器。
 /// <para/> 在工作负载运行期间多次调用 <see cref="Start(CancellationToken)"/> 会取消当前负载并使用最新令牌重新执行;多次调用也只重新执行一次。
 /// <para/> 在工作负载运行期间多次调用 <see cref="Start(CancellationToken)"/> 会取消当前负载并使用最新令牌重新执行;多次调用也只重新执行一次。
 /// </summary>
 /// </summary>
-public abstract class RedoableWorkerBase<TOut>(Func<CancellationToken?, ProgressProvider?, TOut> workload, ProgressProvider? progress = null) : IWorker {
+public abstract class RedoableWorkerBase<TOut>(Func<CancellationToken?, ProgressProvider?, TOut> workload, 
+    ProgressProvider? progress = null, [CallerMemberName] string creatorMemberName = "") : IWorker {
 
 
     // ============================================ 状态与事件 ============================================
     // ============================================ 状态与事件 ============================================
 
 
@@ -93,6 +93,7 @@ public abstract class RedoableWorkerBase<TOut>(Func<CancellationToken?, Progress
             lastToken = cancellationToken;
             lastToken = cancellationToken;
             if (progressOverride != null) Progress = progressOverride;
             if (progressOverride != null) Progress = progressOverride;
             if (running) {
             if (running) {
+                Logger.Info($"{creatorMemberName}:接到重启请求");
                 pendingRedo = true;
                 pendingRedo = true;
                 realCts?.Cancel();
                 realCts?.Cancel();
                 return;
                 return;
@@ -100,10 +101,11 @@ public abstract class RedoableWorkerBase<TOut>(Func<CancellationToken?, Progress
             running = true; idleEvent.Reset();
             running = true; idleEvent.Reset();
             realCts = CancellationTokenSource.CreateLinkedTokenSource(lastToken);
             realCts = CancellationTokenSource.CreateLinkedTokenSource(lastToken);
         }
         }
-        var th = new Thread(_Start) { IsBackground = true, Name = nameof(RedoableWorker) };
+        var th = new Thread(_Start) { IsBackground = true, Name = $"W/{creatorMemberName}" };
         th.Start();
         th.Start();
     }
     }
     private void _Start() {
     private void _Start() {
+        Logger.Info($"{creatorMemberName}:运行开始");
         Started?.Invoke();
         Started?.Invoke();
         while (true) {
         while (true) {
             try {
             try {
@@ -125,13 +127,15 @@ public abstract class RedoableWorkerBase<TOut>(Func<CancellationToken?, Progress
                     running = false; idleEvent.Set();
                     running = false; idleEvent.Set();
                     Progress?.Finish();
                     Progress?.Finish();
                 }
                 }
+                Logger.Info($"{creatorMemberName}:运行成功");
                 Succeeded?.Invoke();
                 Succeeded?.Invoke();
             } catch (Exception ex) {
             } catch (Exception ex) {
                 if (!ex.IsCanceled())
                 if (!ex.IsCanceled())
-                    Logger.Log(ex, $"工作线程执行失败{(pendingRedo ? ",但即将重启,或可忽略" : "")}", pendingRedo ? LogLevel.Info : LogLevel.Warn);
+                    Logger.Log(ex, $"{creatorMemberName}:运行失败{(pendingRedo ? ",但即将重启,或可忽略" : "")}", pendingRedo ? LogLevel.Info : LogLevel.Warn);
                 lock (this) {
                 lock (this) {
                     realCts?.Dispose();
                     realCts?.Dispose();
                     if (pendingRedo) { // 接取重启请求
                     if (pendingRedo) { // 接取重启请求
+                        Logger.Info($"{creatorMemberName}:重启开始");
                         pendingRedo = false;
                         pendingRedo = false;
                         realCts = CancellationTokenSource.CreateLinkedTokenSource(lastToken);
                         realCts = CancellationTokenSource.CreateLinkedTokenSource(lastToken);
                         continue;
                         continue;
@@ -142,6 +146,7 @@ public abstract class RedoableWorkerBase<TOut>(Func<CancellationToken?, Progress
                     Progress?.Skip();
                     Progress?.Skip();
                 }
                 }
                 if (ex.IsCanceled()) {
                 if (ex.IsCanceled()) {
+                    Logger.Info($"{creatorMemberName}:运行已取消");
                     Canceled?.Invoke();
                     Canceled?.Invoke();
                 } else {
                 } else {
                     Failed?.Invoke(ex);
                     Failed?.Invoke(ex);
@@ -156,6 +161,7 @@ public abstract class RedoableWorkerBase<TOut>(Func<CancellationToken?, Progress
     public void Cancel() {
     public void Cancel() {
         lock (this) {
         lock (this) {
             pendingRedo = false;
             pendingRedo = false;
+            Logger.Info($"{creatorMemberName}:接到取消请求");
             realCts?.Cancel();
             realCts?.Cancel();
         }
         }
     }
     }
@@ -181,14 +187,20 @@ public abstract class RedoableWorkerBase<TOut>(Func<CancellationToken?, Progress
 
 
 /// <inheritdoc />
 /// <inheritdoc />
 public class RedoableWorker<TOut> : RedoableWorkerBase<TOut> {
 public class RedoableWorker<TOut> : RedoableWorkerBase<TOut> {
-    public RedoableWorker(Func<CancellationToken?, ProgressProvider?, TOut> workload) : base(workload) { }
-    public RedoableWorker(Func<CancellationToken?, TOut> workload) : base((c, _) => workload(c)) { }
-    public RedoableWorker(Func<TOut> workload) : base((_, _) => workload()) { }
+    public RedoableWorker(Func<CancellationToken?, ProgressProvider?, TOut> workload, [CallerMemberName] string creatorMemberName = "")
+        : base(workload, creatorMemberName: creatorMemberName) { }
+    public RedoableWorker(Func<CancellationToken?, TOut> workload, [CallerMemberName] string creatorMemberName = "")
+        : base((c, _) => workload(c), creatorMemberName: creatorMemberName) { }
+    public RedoableWorker(Func<TOut> workload, [CallerMemberName] string creatorMemberName = "")
+        : base((_, _) => workload(), creatorMemberName: creatorMemberName) { }
 }
 }
 
 
 /// <inheritdoc />
 /// <inheritdoc />
 public class RedoableWorker : RedoableWorkerBase<object?> {
 public class RedoableWorker : RedoableWorkerBase<object?> {
-    public RedoableWorker(Action<CancellationToken?, ProgressProvider?> workload) : base((c, p) => { workload(c, p); return null; }) { }
-    public RedoableWorker(Action<CancellationToken?> workload) : base((c, _) => { workload(c); return null; }) { }
-    public RedoableWorker(Action workload) : base((_, _) => { workload(); return null; }) { }
+    public RedoableWorker(Action<CancellationToken?, ProgressProvider?> workload, [CallerMemberName] string creatorMemberName = "")
+        : base((c, p) => { workload(c, p); return null; }, creatorMemberName: creatorMemberName) { }
+    public RedoableWorker(Action<CancellationToken?> workload, [CallerMemberName] string creatorMemberName = "")
+        : base((c, _) => { workload(c); return null; }, creatorMemberName: creatorMemberName) { }
+    public RedoableWorker(Action workload, [CallerMemberName] string creatorMemberName = "")
+        : base((_, _) => { workload(); return null; }, creatorMemberName: creatorMemberName) { }
 }
 }