Table of Contents

任务沉池使用指南(TaskSink——SubmitFast / Submit)

定位:本仓库唯一合法的 fire-and-forget 任务积木。任何「发完即忘的高频轻量任务」 (RPC 发送/通知/即发即忘清理)都基于任务沉池构建——裸 _ = SomeAsync() 是被禁止的形态 (unobserved exception 诊断黑洞 + Task 洪水打满公共池)。本文覆盖:两形态选型、API 全貌、 契约与硬性要求、仓库真实范例。长驻循环/队列消费见 worker-loop.md; 要进度/结果句柄的长操作用 AsyncOperation 体系(Runtime 侧)。


0. 铁律:禁止裸 _ = SomeAsync()

裸丢弃的两个雷:

  1. 异常不可观测:任务挂了没有栈、没有日志,什么都没有(unobserved——楔死取证时 找不到失败记录)。
  2. Task 洪水:瞬间大量任务丢弃打满公共任务池——卡死、GC 停止。

任务沉池在提交点把两个雷都堵死:异常集中兜底(日志 + onFaulted + 故障计数)+ 在途可观测(InFlightCount)+ Dispose 有界收尾(不悬挂半途任务)。


1. 两形态选型

SubmitFast(高性能路径) Submit(安全通用路径)
启动 内联——任务体第一段(到第一个 await)在提交线程同步执行 池上——Task.Run 全程(含第一段),提交线程零占用
快路径 同步完成的任务 ≈ 0 开销(0 分配) 无(每次固定 ~400ns 调度+包装)
契约 第一段必须轻量非阻塞(阻塞拖住提交方) 第一段任意(未知/第三方回调)

选择树:要队列/限流/优先级 → WorkerLoop;要进度句柄 → AsyncOperation; 第一段轻量可控(自有代码)→ SubmitFast;第一段不可控 → Submit; 要身份/单任务取消/等待完成 → 不是本原语的语义(协议层自持状态;长稳定循环走 专用线程 + AsyncPump 泵域,时间驱动唤醒走 DeadlineRegistry——任务沉池只收 轻量高频即发即忘)。

2. 快速上手

// 装配(字段持有——Dispose 编排收尾)
private readonly TaskSink _sends = new(name: "raft-sends", logger: logger);

// 提交(fire-and-forget——void,零仪式;同步/异步上下文都可直接调)
_sends.SubmitFast(ct => _transport.SendAsync(peer, rpc, ct));

// 收尾(宿主 DisposeAsync 里编排——取消传播 + 有界等待在途)
await _sends.DisposeAsync();

构造参数(两形态同签名):

参数 默认 说明
string? name 类名 诊断标识(日志区分多实例)
ILogger? logger null 未捕获异常兜底记录(null = 静默)
Action<Exception>? onFaulted null 未捕获异常回调(logger 之后调用——测试断言/高级消费方)
TimeSpan? drainTimeout 5s Dispose 等在途完成的超时(超时 LogWarning 不抛——尽力而为)

诊断属性:InFlightCount(在途数)/ SubmittedCount(累计提交)/ FaultedCount (累计故障——洪水率与黑洞率可量化:Faulted/Submitted)。

3. 契约

一句话:提交即放手

保证的

  • 异常收口不外泄:任务体漏 catch 由池兜底——LogWarning + onFaulted + FaultedCount,不悬挂 unobserved。
  • 组生命周期:Dispose = 取消传播(组级 ct)+ 有界 drain(等在途归零,超时告警不抛)。
  • void 零仪式:提交无返回值、无句柄、无等待。

不保证的(fire-and-forget 的本义):

  • 执行:已释放即拒(ObjectDisposedException fail-fast)、池拒绝、进程终—— 提交成功 ≠ 必然执行。
  • 完成通知:丢弃静默,没有逐任务回调/句柄——只能事后从计数器观测 (InFlightCount 归零 / FaultedCount 增量)。
  • 顺序:提交序 ≠ 执行序(池上路径并发跑;内联路径第一段先行但续段回池)。

取消归一:所有 OperationCanceledException(组取消 Dispose 收尾/任务体业务取消) 归正常完成,不进故障计数。

4. 硬性要求

  1. 禁止裸 _ = SomeAsync()——一律经任务沉池(本文件 §0)。
  2. SubmitFast 的第一段契约——提交线程执行,必须轻量非阻塞;做不到换 Submit 或 WorkerLoop。
  3. 宿主 Dispose 必须编排池收尾DisposeAsync 传递)——不收尾则进程退出前在途 任务不可观测。
  4. 不做限流/排队(要排队语义用 WorkerLoop)——消费方井喷需自限;提交速率天然有界 的场景(单事件循环串行产生)无需处理。