Agent 长任务断点续传演示-Polly超时-重试-熔断

参考:https://www.cnblogs.com/chenwolong/p/22395330

背景:一个长任务,假设由300个任务组成,各个任务之间没有相互依赖,在执行过程中,如果第197个任务失败了,怎么弄?

记录失败日志,后续手动执行第197个任务。

如果任务之间有依赖,则第197个任务失败后,就不能继续向下执行了!

实际应用中长任务执行通常占用时间较长,过程中难免遇到网络波动等影响任务执行的因素,因此,需要一套执行机制确保尽可能的成功执行任务!

本篇采用-Polly超时-重试-熔断机制进行项目展示!

关于Polly超时-重试-熔断机制,可参考:https://www.cnblogs.com/chenwolong/p/22395330

🏗️ 系统架构总览

┌─────────────────────────────────────────────────────────────────┐
│                         Program.Main                            │
│                    (程序入口 + 调度中心)                         │
└─────────────────────────────────────────────────────────────────┘
                              │
              ┌───────────────┼───────────────┐
              ▼               ▼               ▼
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
│ InMemoryProgress  │ │    TaskExecutor   │ │ HeartbeatMonitor  │
│     Store         │ │                   │ │                   │
│  (进度存储服务)    │ │   (任务执行器)     │ │   (心跳监控器)     │
└───────────────────┘ └───────────────────┘ └───────────────────┘
         │                      │                      │
         │                      ▼                      │
         │            ┌───────────────────┐           │
         │            │  Polly 策略组合    │           │
         │            │  (重试 + 熔断 + 超时) │           │
         │            └───────────────────┘           │
         │                      │                      │
         ▼                      ▼                      ▼
┌─────────────────────────────────────────────────────────────────┐
│                        数据模型层                                │
│  ┌─────────────────────┐       ┌─────────────────────────────┐  │
│  │      TaskItem       │       │        TaskProgress         │  │
│  │  (任务项模型)        │       │      (任务进度模型)          │  │
│  └─────────────────────┘       └─────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘

📦 类详解

1️⃣ Program - 程序入口

项目说明
职责 程序启动、DI 容器配置、任务调度、优雅退出
依赖 InMemoryProgressStoreTaskExecutorHeartbeatMonitor
关键代码 Host.CreateDefaultBuilder()Console.CancelKeyPress

核心流程:

 

核心目标 

1. 配置 DI 容器 (注册服务)
   ↓
2. 初始化存储 (InitializeAsync)
   ↓
3. 恢复进度 (LoadProgressAsync)
   ↓
4. 创建任务列表
   ↓
5. 启动心跳监控 (MonitorAsync)
   ↓
6. 执行批量任务 (ExecuteBatchAsync)
   ↓
7. 保存最终进度
   ↓
8. 分析失败任务

2️⃣ InMemoryProgressStore - 进度存储服务

项目说明
职责 任务进度持久化 (内存模拟)、断点恢复、失败任务查询
依赖 ILogger<InMemoryProgressStore>
存储结构 static List<TaskItem> + static TaskProgress
线程安全 ✅ lock (_lock)

核心方法:

方法作用调用时机
InitializeAsync() 清空历史数据 程序启动
SaveProgressAsync() 保存进度 每 10 个任务保存一次
LoadProgressAsync() 恢复进度 程序启动/重启
GetAllTasks() 获取所有任务 (调试) 调试时

数据流向:

askExecutor ──SaveProgressAsync──> InMemoryProgressStore
                                        │
                                        ├── _taskStore (任务详情)
                                        │
                                        └── _summaryProgress (进度摘要)

3️⃣ TaskExecutor - 任务执行器

项目说明
职责 执行单个任务、批量执行、容错处理 (重试 + 熔断 + 超时)
依赖 InMemoryProgressStoreILogger<TaskExecutor>HeartbeatMonitor
核心组件 Polly 策略组合 (AsyncPolicyWrap)

Polly 策略组合:

┌─────────────────────────────────────────────────────────────┐
│                    PolicyWrap                                │
│  ┌───────────────────────────────────────────────────────┐  │
│  │              TimeoutPolicy (20 秒)                      │  │
│  │  ┌─────────────────────────────────────────────────┐  │  │
│  │  │            CircuitBreakerPolicy (连续 2 次失败)    │  │  │
│  │  │  ┌───────────────────────────────────────────┐  │  │  │
│  │  │  │           RetryPolicy (3 次指数退避)         │  │  │  │
│  │  │  │  ┌─────────────────────────────────────┐  │  │  │  │
│  │  │  │  │      SimulateTaskExecutionAsync     │  │  │  │  │
│  │  │  │  └─────────────────────────────────────┘  │  │  │  │
│  │  │  └───────────────────────────────────────────┘  │  │  │
│  │  └─────────────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

执行流程:

ExecuteTaskAsync(任务)
    ↓
PolicyWrap.ExecuteAsync()
    ↓
Timeout 检查 (20 秒内必须完成)
    ↓
CircuitBreaker 检查 (熔断器是否打开)
    ↓
Retry 执行 (最多 3 次重试)
    ↓
SimulateTaskExecutionAsync (实际执行)
    ↓
成功 → IsCompleted = true
失败 → ErrorMessage = 异常消息

4️⃣ HeartbeatMonitor - 心跳监控器

项目说明
职责 后台监控任务执行进度、超时告警
依赖 ILogger<HeartbeatMonitor>
监控方式 后台独立线程,每分钟检查一次
超时阈值 5 分钟无进展触发告警

工作原理:

┌─────────────────────────────────────────────────────────────┐
│                   HeartbeatMonitor                           │
│                                                              │
│  _lastProgressTime (记录最后进度时间)                         │
│         │                                                    │
│         ▼                                                    │
│  ┌──────────────────────────────────────────────────────┐   │
│  │              MonitorAsync (后台线程)                   │   │
│  │  while (!token.IsCancellationRequested)              │   │
│  │      ↓                                                │   │
│  │  Delay 1 分钟                                          │   │
│  │      ↓                                                │   │
│  │  elapsed = Now - _lastProgressTime                    │   │
│  │      ↓                                                │   │
│  │  if (elapsed > 5 分钟) → 触发告警 ⚠️                    │   │
│  └──────────────────────────────────────────────────────┘   │
│                                                              │
│  RecordProgress() ← TaskExecutor 每次保存进度时调用           │
│      ↓                                                       │
│  _lastProgressTime = DateTime.Now                            │
└─────────────────────────────────────────────────────────────┘

5️⃣ TaskItem - 任务项模型

属性类型说明
Id ulong 任务唯一标识
Content string 任务描述
IsCompleted bool 是否完成
RetryCount int 重试次数
LastAttemptTime DateTime? 最后尝试时间
ErrorMessage string? 错误消息
Embedding float[1536] 向量嵌入 (用于相似度检索)
Category string 任务分类

6️⃣ TaskProgress - 任务进度模型

属性类型说明
ProgressId string 进度标识
TotalCount long 总任务数
CompletedCount long 已完成数量
LastSavedBatch long 上次保存的批次号
FailedTaskIds List<ulong> 失败任务 ID 列表
StartTime DateTime 开始时间
LastUpdateTime DateTime? 最后更新时间
Status string 状态 (Running/Completed/Interrupted)

 

🎯 每个类的核心作用总结

类名一句话总结类比
Program 程序入口 + 调度中心 项目经理 (负责启动、协调、收尾)
InMemoryProgressStore 进度数据库 (内存版) 档案室 (存进度、查历史)
TaskExecutor 任务执行引擎 + 容错处理 施工队 (干活 + 重试 + 熔断保护)
HeartbeatMonitor 后台监控器 监工 (盯着进度,卡住就报警)
TaskItem 任务数据模型 工单 (每个任务的详细信息)
TaskProgress 进度数据模型 进度表 (整体完成情况)

💡 设计亮点

设计点体现位置好处
依赖注入 所有服务通过 DI 容器注册 解耦、易测试、易替换
异步编程 所有 I/O 操作都是 async/await 不阻塞主线程
线程安全 lock (_lock) 保护共享数据 多线程并发不冲突
策略模式 Polly 策略组合 容错逻辑清晰、可配置
事件驱动 HeartbeatMonitor.OnTimeoutAlert 告警可扩展 (钉钉/邮件/短信)
断点续传 SaveProgressAsync + LoadProgressAsync 中断后可恢复

 

核心代码

 
using ConsoleApp1;
using ConsoleApp7.Models;
using ConsoleApp7.services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; 
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using System.ComponentModel;
using System.Diagnostics;
using System.Text.Json.Serialization;
using System.Timers;

namespace ConsoleApp5
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("╔════════════════════════════════════════╗");
            Console.WriteLine("║ 长任务断点续传演示 ║");
            Console.WriteLine("╚════════════════════════════════════════╝\n");

            var host = Host.CreateDefaultBuilder(args)
                .ConfigureServices(services =>
                {
                    services.AddSingleton<InMemoryProgressStore>();
                    services.AddSingleton<TaskExecutor>();
                    services.AddSingleton<HeartbeatMonitor>();
                    services.AddLogging(b => b.AddConsole().SetMinimumLevel(LogLevel.Information));
                })
                .Build();

            var store = host.Services.GetRequiredService<InMemoryProgressStore>();
            var executor = host.Services.GetRequiredService<TaskExecutor>();
            var monitor = host.Services.GetRequiredService<HeartbeatMonitor>();

            // ✅ 订阅心跳超时告警事件
            monitor.OnTimeoutAlert += (sender, alertMsg) =>
            {
                // 可扩展为钉钉/邮件/短信告警
                Console.WriteLine($"🚨 收到心跳告警:{alertMsg}");
            };

            await store.InitializeAsync();

            var progress = new TaskProgress
            {
                TotalCount = 30,
                StartTime = DateTime.Now,
                Status = "Running"
            };
            var tasks = Enumerable.Range(1, (int)progress.TotalCount)
                .Where(i => i > progress.CompletedCount)
                .Select(i => new TaskItem
                {
                    Id = (ulong)i,
                    Content = $"任务 #{i} - 数据处理",
                    Category = i % 3 == 0 ? "batch_A" : "batch_B"
                })
                .ToList();

            Console.WriteLine($"🚀 开始执行 {tasks.Count} 个任务...\n");

            using var cts = new CancellationTokenSource(); 
            var monitorTask = monitor.MonitorAsync(cts.Token);

            try
            {
                await executor.ExecuteBatchAsync(tasks, progress, cts.Token);
                Console.WriteLine($"\n✅ 完成!成功:{progress.CompletedCount}, 失败:{progress.FailedTaskIds.Count}");
                progress.Status = "Completed";
                progress.LastUpdateTime = DateTime.Now;
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine($"\n💾 已中断,进度已保存到内存。下次运行将自动恢复。");
                progress.Status = "Interrupted";
            }
            finally
            {
                var completedTasks = tasks.Where(t => t.LastAttemptTime != null).ToList();
                if (completedTasks.Count > 0)
                {
                    await store.SaveProgressAsync(progress, completedTasks);
                }
            } 
             
            Console.WriteLine("\n按任意键退出...");
            Console.ReadKey();
        }
    }
}

Models

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp7.Models
{
    /// <summary>
    /// 任务项模型
    /// </summary>
    public class TaskItem
    {
        /// <summary>
        /// 任务唯一标识(ulong 类型,可隐式转为 PointId)
        /// </summary>
        public ulong Id { get; set; }

        /// <summary>
        /// 任务内容描述
        /// </summary>
        public string Content { get; set; } = string.Empty;

        /// <summary>
        /// 是否已完成
        /// </summary>
        public bool IsCompleted { get; set; }

        /// <summary>
        /// 重试次数(最多 3 次)
        /// </summary>
        public int RetryCount { get; set; }

        /// <summary>
        /// 最后尝试时间
        /// </summary>
        public DateTime? LastAttemptTime { get; set; }

        /// <summary>
        /// 错误消息(失败时记录)
        /// </summary>
        public string? ErrorMessage { get; set; }

        /// <summary>
        /// 向量嵌入(用于 Qdrant 相似度检索)
        /// 维度:1536(text-embedding-v2)
        /// </summary>
        public float[] Embedding { get; set; } = new float[1536];

        /// <summary>
        /// 任务分类(用于筛选)
        /// </summary>
        public string Category { get; set; } = "default";
    }

    /// <summary>
    /// 任务进度模型
    /// 用于断点续传和状态追踪
    /// </summary>
    public class TaskProgress
    {
        /// <summary>
        /// 进度标识(如:batch_001)
        /// </summary>
        public string ProgressId { get; set; } = "batch_001";

        /// <summary>
        /// 总任务数
        /// </summary>
        public long TotalCount { get; set; }

        /// <summary>
        /// 已完成数量
        /// </summary>
        public long CompletedCount { get; set; }

        /// <summary>
        /// 上次保存的批次号(每 10 个任务保存一次)
        /// </summary>
        public long LastSavedBatch { get; set; }
         
        /// <summary>
        /// 失败的任务 ID 列表(ulong 类型)
        /// </summary>
        public List<ulong> FailedTaskIds { get; set; } = new List<ulong>();


        /// <summary>
        /// 开始时间
        /// </summary>
        public DateTime StartTime { get; set; }

        /// <summary>
        /// 最后更新时间
        /// </summary>
        public DateTime? LastUpdateTime { get; set; }

        /// <summary>
        /// 状态:Running/Completed/Failed
        /// </summary>
        public string Status { get; set; } = "Running";
    }
}

Services

using ConsoleApp7.Models; 
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
using Polly;
using Polly.CircuitBreaker;
using Polly.Retry;
using Polly.Timeout;
using Polly.Wrap; 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp7.services
{
    /// <summary>
    /// 内存进度存储服务(模拟 Qdrant,用于演示)
    /// ✅ 使用 static List<T> 存储
    /// </summary>
    public class InMemoryProgressStore
    {
        private readonly ILogger<InMemoryProgressStore> _logger;

        // ✅ 静态列表,模拟持久化存储
        private static readonly List<TaskItem> _taskStore = new List<TaskItem>();
        private static TaskProgress? _summaryProgress = null;
        private static readonly object _lock = new object();

        public InMemoryProgressStore(ILogger<InMemoryProgressStore> logger)
        {
            _logger = logger;
        }

        /// <summary>
        /// 初始化存储(清空历史数据)
        /// </summary>
        public Task InitializeAsync()
        {
            lock (_lock)
            {
                _taskStore.Clear();
                _summaryProgress = null;
                Console.WriteLine("✅ 内存存储初始化完成");
            }
            return Task.CompletedTask;
        }

        /// <summary>
        /// 保存进度到内存
        /// </summary>
        public Task SaveProgressAsync(TaskProgress progress, List<TaskItem> batch)
        {
            lock (_lock)
            {
                // 保存任务详情
                foreach (var task in batch)
                {
                    var existing = _taskStore.FirstOrDefault(t => t.Id == task.Id);
                    if (existing != null)
                    {
                        _taskStore.Remove(existing);
                    }
                    _taskStore.Add(task);
                }

                // 保存进度摘要
                _summaryProgress = new TaskProgress
                {
                    ProgressId = progress.ProgressId,
                    TotalCount = progress.TotalCount,
                    CompletedCount = progress.CompletedCount,
                    LastSavedBatch = progress.LastSavedBatch,
                    FailedTaskIds = new List<ulong>(progress.FailedTaskIds),
                    StartTime = progress.StartTime,
                    LastUpdateTime = DateTime.Now,
                    Status = progress.Status
                };

                Console.WriteLine($"💾 进度已保存:完成 {progress.CompletedCount}/{progress.TotalCount}");
            }
            return Task.CompletedTask;
        }

      
        /// <summary>
        /// 获取所有任务(调试用)
        /// </summary>
        public List<TaskItem> GetAllTasks()
        {
            lock (_lock)
            {
                return new List<TaskItem>(_taskStore);
            }
        }
    }

    /// <summary>
    /// 任务执行器
    /// ✅ 集成 Polly 重试 + 熔断 + 超时
    /// </summary>
    public class TaskExecutor
    {
        private readonly InMemoryProgressStore _store;
        private readonly ILogger<TaskExecutor> _logger;
        private readonly HeartbeatMonitor _monitor; // ✅ 新增:注入心跳监控

        // ✅ 全部使用非泛型
        private readonly AsyncRetryPolicy _retryPolicy;
        private readonly AsyncCircuitBreakerPolicy _circuitBreaker;
        private readonly AsyncTimeoutPolicy _timeoutPolicy;
        private readonly AsyncPolicyWrap _policyWrap; // ✅ 非泛型

        public TaskExecutor(InMemoryProgressStore store, ILogger<TaskExecutor> logger, HeartbeatMonitor monitor)
        {
            _store = store;
            _logger = logger;
            _monitor = monitor;

            // ✅ 重试:最多 3 次,指数退避(非泛型)
            _retryPolicy = Policy
                .Handle<Exception>()
                .WaitAndRetryAsync(
                    retryCount: 3,
                    sleepDurationProvider: retry =>
                    TimeSpan.FromSeconds(Math.Pow(1.1, retry)),
                    onRetry: (outcome, timeSpan, retryNumber, context) =>
                    {
                        _logger.LogWarning(
                            "任务 {TaskId} 重试 {Retry}/{Max},等待 {Wait}s,原因:{Error}",
                            context["TaskId"], retryNumber, 3,
                            timeSpan.TotalSeconds, outcome.GetBaseException()?.Message);
                    }
                );

            // ✅ 熔断:连续失败 2 次 → 熔断 30 秒(非泛型)
            _circuitBreaker = Policy
                .Handle<Exception>()
                .CircuitBreakerAsync(
                    exceptionsAllowedBeforeBreaking: 2,
                    durationOfBreak: TimeSpan.FromSeconds(30),
                    onBreak: (outcome, timeSpan) =>
                    {
                        _logger.LogError("⚠️ 熔断器打开!连续失败 2 次,暂停 {Seconds}s", timeSpan.TotalSeconds);
                    },
                    onReset: () =>
                    {
                        _logger.LogInformation("✅ 熔断器复位,恢复正常");
                    }
                );

            // ✅ 超时:20 秒(非泛型)
            _timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromSeconds(20));

            // ✅ 组合策略(返回非泛型 AsyncPolicyWrap)
            _policyWrap = Policy.WrapAsync(_timeoutPolicy, _circuitBreaker, _retryPolicy);
        }

        /// <summary>
        /// 执行单个任务(带重试 + 超时 + 熔断)
        /// </summary>
        public async Task<TaskItem> ExecuteTaskAsync(TaskItem task, CancellationToken token)
        {
            try
            {
                await _policyWrap.ExecuteAsync(
                    async (ctx) =>
                    {
                        task.LastAttemptTime = DateTime.Now;
                        await SimulateTaskExecutionAsync(task, token);
                        task.IsCompleted = true;
                        task.ErrorMessage = null;
                    },
                    new Context { ["TaskId"] = task.Id }
                );

                return task;
            }
            catch (BrokenCircuitException)
            {
                task.ErrorMessage = "熔断器打开,服务暂时不可用";
                task.RetryCount++;
                return task;
            }
            catch (TimeoutRejectedException)
            {
                task.ErrorMessage = "任务超时(20 秒)";
                task.RetryCount++;
                return task;
            }
            catch (Exception ex)
            {
                task.ErrorMessage = ex.Message;
                task.RetryCount++;
                return task;
            }
        }

        /// <summary>
        /// 批量执行任务(带进度保存)
        /// </summary>
        public async Task ExecuteBatchAsync(List<TaskItem> tasks, TaskProgress progress, CancellationToken token)
        {
            var batch = new List<TaskItem>();

            foreach (var task in tasks)
            {
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("\n⏹️ 任务已取消,保存当前进度...");
                    break;
                }

                var result = await ExecuteTaskAsync(task, token);

                if (result.IsCompleted)
                {
                    progress.CompletedCount++;
                }
                else
                {
                    progress.FailedTaskIds.Add(task.Id);
                }

                batch.Add(result);

                if (batch.Count >= 10)
                {
                    progress.LastSavedBatch++;
                    progress.LastUpdateTime = DateTime.Now;
                    await _store.SaveProgressAsync(progress, batch);
                    _monitor.RecordProgress(); // ✅ 修复:告诉心跳"我还活着"
                    batch.Clear();
                }
            }

            if (batch.Count > 0)
            {
                progress.LastSavedBatch++;
                await _store.SaveProgressAsync(progress, batch);
                _monitor.RecordProgress(); // ✅ 修复:最后一次保存也要调用
            }
        }

        /// <summary>
        /// 模拟任务执行(随机失败)
        /// </summary>
        private async Task SimulateTaskExecutionAsync(TaskItem task, CancellationToken token)
        {
            await Task.Delay(Random.Shared.Next(100, 200), token);

            // 降低失败率方便演示(80% → 30%)
            if (Random.Shared.NextDouble() < 0.8)
            {
                throw new Exception($"任务 {task.Id} 执行失败(模拟网络错误)");
            }
             
        }
    }
}


/// <summary>
/// 心跳检测器
/// ✅ 监控任务执行进度
/// ✅ 长时间无进展时告警
/// </summary>
public class HeartbeatMonitor
{
    private readonly ILogger<HeartbeatMonitor> _logger;
    private readonly TimeSpan _timeoutThreshold = TimeSpan.FromMinutes(5); // 5 分钟阈值
    private DateTime _lastProgressTime;

    /// <summary>
    /// 超时告警事件
    /// </summary>
    public event EventHandler<string>? OnTimeoutAlert;

    public HeartbeatMonitor(ILogger<HeartbeatMonitor> logger)
    {
        _logger = logger;
        _lastProgressTime = DateTime.Now;
    }

    /// <summary>
    /// 记录进度(每次保存进度时调用)
    /// </summary>
    public void RecordProgress()
    {
        _lastProgressTime = DateTime.Now;
    }

    /// <summary>
    /// 后台监控任务
    /// ✅ 每分钟检查一次进展
    /// </summary>
    public async Task MonitorAsync(CancellationToken token)
    {
        while (!token.IsCancellationRequested)
        {
            await Task.Delay(TimeSpan.FromMinutes(1), token);

            var elapsed = DateTime.Now - _lastProgressTime;
            if (elapsed > _timeoutThreshold)
            {
                var alert = $"⚠️ 心跳超时!已 {elapsed.TotalMinutes:F1} 分钟无进展";
                _logger.LogWarning(alert);
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine(alert);
                Console.ResetColor();

                OnTimeoutAlert?.Invoke(this, alert);
            }
        }
    }
}
 

项目引用

<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net8.0</TargetFramework>
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
		<NoWarn>$(NoWarn);NU5104</NoWarn>
	</PropertyGroup>


	<ItemGroup>
		<!-- ✅ Semantic Kernel 核心 -->
		<PackageReference Include="Microsoft.SemanticKernel" Version="1.78.0" />
		<PackageReference Include="Microsoft.SemanticKernel.Connectors.OpenAI" Version="1.78.0" />
		<PackageReference Include="Newtonsoft.Json" Version="13.0.5-beta1" />
 
		<!-- ✅ 阿里云 DashScope(通义千问) -->
		<PackageReference Include="Sdcb.DashScope" Version="2.0.0" />

		<!-- ✅ Polly 重试机制 -->
		<PackageReference Include="Polly" Version="8.4.0" />

		<!-- ✅ 依赖注入 -->
		<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
	</ItemGroup>

</Project>

  

 

posted @ 2026-08-12 09:36  天才卧龙  阅读(7)  评论(0)    收藏  举报