rusty-cat 分片并发下载完全指南

4 阅读20分钟

rusty-cat 分片并发下载完全指南(Rust 小白版)

本文面向 刚接触 Rust、想快速把「大文件分片并发下载 + 断点续传」跑起来 的开发者。 每段代码都能直接复制到你的项目里编译运行,需要替换的地方都写了中文注释。 配套阅读:《rusty-cat 分片并发上传完全指南》


目录

  1. 下载功能能帮你做什么
  2. 第一步:加依赖
  3. 5 分钟跑通第一个下载(完整可运行程序)
  4. 下载是怎么工作的:HEAD + Range GET
  5. 开启并发下载——with_max_parts_in_flight + with_total_size
  6. 并发下载配方(复制即用)
  7. 下载云存储对象(OSS / Azure)的两种姿势
  8. 并发下载的断点续传:.rcdl 边车文件
  9. 进度、暂停、恢复、取消
  10. 内存占用与参数怎么选
  11. 错误处理与自动重试
  12. 常见问题排查表(FAQ)
  13. 附录:配置项速查表

1. 下载功能能帮你做什么

rusty-cat 的下载能力围绕「大文件的可断点续传下载」:

  • 分片下载:用 HTTP Range 请求把一个大文件分成很多小块拉取;
  • 并发下载:同一个文件的多个 range 分片可以同时拉,把带宽跑满;
  • 断点续传:进程被杀、崩溃、重启后能接着下,不用从头再来;
  • 进度回调 / 暂停 / 恢复 / 取消:和上传共用同一套心智模型;
  • 自动重试 + 退避:网络抖动自动重试,且区分「瞬时错误」(重试)和「硬错误」(快速失败)。

好消息是:下载不需要任何云厂商密钥。只要你有一个能响应 HTTP Range 请求的 URL(公网直链、阿里云预签名 URL、Azure SAS URL 都行),就能用内置的默认下载器跑起来。

一句话记住用法:创建 MeowClient → 用 DownloadPounceBuilder 构建下载任务 → 提交 → 收进度 → close()


2. 第一步:加依赖

最基础的并发下载不需要任何 feature,基础 crate 就够了:

[dependencies]
rusty-cat = "0.2.4"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

只有当你要用「provider 专属的下载协议」(比如用 AccessKey 直接签名去下 OSS 对象)时,才需要开对应 feature:

# 仅当你要用 provider 专属下载协议时才需要:
# rusty-cat = { version = "0.2.4", features = ["aliyun-oss-direct"] }     # OSS 直下
# rusty-cat = { version = "0.2.4", features = ["aliyun-oss-presigned"] }  # OSS 预签名 range 下载
# rusty-cat = { version = "0.2.4", features = ["azure-blob-direct"] }     # Azure 直下
# rusty-cat = { version = "0.2.4", features = ["azure-blob-sas"] }        # Azure SAS range 下载

先记住一个关键结论(第 5、7 节会展开):想要「并发」下载,用的是内置默认下载器 + 一个签好名的 GET URL,不需要 provider 下载协议。provider 专属的下载协议只能串行。


3. 5 分钟跑通第一个下载(完整可运行程序)

下面是一个完整main.rs,把一个公网文件下载到本地。把 URL 换成你自己的可下载链接,cargo run 即可。

use std::time::Duration;

use rusty_cat::api::{DownloadPounceBuilder, FileTransferRecord, MeowClient, MeowConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    // 提示:确保本地保存目录(这里是 ./downloads)已经存在
    let config = MeowConfig::builder()
        .max_download_concurrency(2)          // 同时最多下 2 个「文件」
        .http_timeout(Duration::from_secs(30))
        .build()?;
    let client = MeowClient::new(config);

    let task = DownloadPounceBuilder::new(
        "example.bin",                        // 展示用文件名
        "./downloads/example.bin",            // 本地保存路径
        1024 * 1024,                          // 分片大小 = 1 MiB
        "https://example.com/example.bin",    // 下载 URL(换成你的)
    )
    .with_max_chunk_retries(3)                // 每片失败最多再重试 3 次
    .build();

    // enqueue_and_wait:提交并一直等到跑完,最省事
    let outcome = client
        .enqueue_and_wait(task, |record: FileTransferRecord| {
            println!(
                "下载进度 {:.1}%  状态 {:?}",
                record.progress() * 100.0,
                record.status()
            );
        })
        .await?;

    println!("下载完成!task_id={}", outcome.task_id);

    // 关闭客户端(必须!)
    client.close().await?;
    Ok(())
}

几个要点:

  • DownloadPounceBuilder::new 的四个参数依次是:展示文件名、本地保存路径、分片大小、下载 URL
  • 上面这段是串行下载(没开并发),任何支持 Range 的 URL 都能跑。开并发见第 5 节。
  • enqueue_and_wait 成功返回 TaskOutcome,失败 / 取消返回 Err,用 ? 即可。
  • 一定要 client.close().await:优雅关闭后台调度、发完缓冲事件。别指望 Drop 兜底。
  • 目标目录要先存在(比如先 std::fs::create_dir_all("./downloads")?)。

4. 下载是怎么工作的:HEAD + Range GET

理解这套机制,能帮你少踩很多坑:

  1. 准备阶段(prepare):SDK 先发一个 HEAD 请求,从响应的 Content-Length 得知文件总大小,据此把文件切成一格一格的 range 网格。
  2. 传输阶段:对每一格发 GET 请求,带 Range: bytes=起-止 头,服务端必须返回 206 Partial Content
  3. 落盘:每个 range 响应体直接写到本地文件的绝对偏移位置。

🖼️ 【配图占位 D1|并发下载数据流(HEAD + 并行 Range GET)】 建议配图:客户端先发一次 HEAD 拿到 Content-Length(若已 with_total_size 则跳过这步);随后把文件切成 range 网格,4 条并行箭头表示同时发出的 Range GET(各要一段 bytes=起-止,服务端回 206);每段响应体写入本地预撑文件的对应绝对偏移。图注:各分片完全独立、可乱序、可并发。 临时 ASCII 草图:

客户端 ──HEAD──▶ 服务端(拿 Content-Length;有 with_total_size 则跳过)
       ═══GET bytes=0-2M═════▶ ┐
       ═══GET bytes=2M-4M════▶ ├─ 4 段并行,各回 206
       ═══GET bytes=4M-6M════▶ │
       ═══GET bytes=6M-8M════▶ ┘
       ▼ 每段写入本地文件的绝对偏移
本地文件 [__0-2M__][__2M-4M__][__4M-6M__][__6M-8M__]

由此推出两条硬规则:

  • 服务端必须支持 Range。如果服务端无视 Range、返回了整个文件(200 OK),会被判定为 InvalidRange 硬错误。
  • 下载的 HTTP 方法不可配置(固定 HEAD + GET)。如果某个网关需要非标准动作,就自己实现 BreakpointDownload

关于给 GETRange 头会不会破坏「URL 里带签名」的鉴权(预签名 / SAS):不会。按 RFC 7233,Range 放在请求头里,而预签名 / SAS 的签名只覆盖 URL 和 query 参数、不覆盖任意请求头。所以同一个签好名的 range URL 可以被切成任意多个 Range 分片、甚至并发拉取。


5. 开启并发下载——with_max_parts_in_flight + with_total_size

和上传一样,两个「并发」是独立的,别搞混:

旋钮作用范围默认控制什么
MeowConfig::builder().max_download_concurrency(k)整个客户端2同时下 几个文件
DownloadPounceBuilder::with_max_parts_in_flight(n)单个文件内部1一个文件的 几个 range 分片 同时拉

两者相乘:max_download_concurrency(3) 且每个文件 with_max_parts_in_flight(4),则最多 3 × 4 = 12 个 range 请求同时在飞。没有全局上限,请自己控制乘积。

并发下载的三个前置条件(并发闸门)

设了 with_max_parts_in_flight(8) 并不保证 真并发。只有 同时满足以下三条 才走并发路径:

  1. n > 10 归一化为 1);
  2. 文件总大小已知——这是下载最关键的一条,两种方式满足:
    • 显式调 with_total_size(总字节数)(推荐,还能顺便跳过 HEAD),或
    • HEAD 探测出来(服务端必须返回正数 Content-Length)。
  3. 下载协议是「并发安全」的

哪个下载协议支持并发?(上传 / 下载不对称,务必记住)

下载协议并发安全?说明
StandardRangeDownload(内置默认)✅ 是标准 RFC 7233 Range 请求,每片完全独立、写到绝对偏移
AliOssDirectDownload❌ 否provider 专属协议,只能串行
AzureBlobDirectDownload❌ 否同上
PresignedRangeDownload(OSS 预签名 / Azure SAS)❌ 否同上
你自己实现的 BreakpointDownload❌ 否(默认)除非显式声明支持

⚠️ 上传和下载不对称! 上传时,四种 provider 上传协议并发安全;但下载时,唯一并发安全的是内置的 StandardRangeDownload

要并发下载一个 OSS / Azure 对象,做法是:把一个签好名的 GET URL(阿里云预签名 URL、Azure SAS URL、或公网直链)直接喂给默认下载器——也就是不要调 with_breakpoint_download(...)。一旦挂了 provider 下载协议,就会静默变回串行。

另一个致命坑:如果你开了并发(n > 1)却没让总大小可知——既没调 with_total_sizeHEAD 又拿不到正数 Content-Length——那么任务会在准备阶段直接失败MissingOrInvalidContentLengthFromHead),不会悄悄退回串行。所以对那些不支持 HEAD 的签名 URL,请务必用 with_total_size 显式给出总大小。


6. 并发下载配方(复制即用)

这是本文的核心配方:用默认下载器 + 一个签好名的 GET URL,实现并发下载。

use rusty_cat::api::{DownloadPounceBuilder, MeowClient, MeowConfig};

// signed_get_url:阿里云预签名 / Azure SAS / 公网 GET URL
// total_size:文件总字节数(从你的元数据接口 / check 接口拿到)
async fn download_concurrent(
    signed_get_url: &str,
    total_size: u64,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let client = MeowClient::new(MeowConfig::default());

    let task = DownloadPounceBuilder::new(
        "movie.mp4",
        "./downloads/movie.mp4",
        2 * 1024 * 1024,        // 2 MiB range 分片
        signed_get_url,
    )
    .with_total_size(total_size)     // 条件2:总大小已知,顺便跳过 HEAD
    .with_max_parts_in_flight(4)     // 条件1:最多 4 个 Range GET 并发
    // 千万不要调 .with_breakpoint_download(...),要保持默认的 StandardRangeDownload
    .build();

    client
        .enqueue_and_wait(task, |r| println!("{:.1}%", r.progress() * 100.0))
        .await?;
    client.close().await?;
    Ok(())
}

并发下载的几条关键规则:

  • 一定要给总大小with_total_size(total) 满足前置条件 2,并跳过 HEAD(对那些不响应 HEAD 的预签名 / SAS URL 尤其重要)。
  • 服务端必须对 Range 返回 206。返回 200 OK(无视 range)会被判为 InvalidRange 硬错误。
  • 要加 provider 头就用 with_headers(...),绝不要去改 URL。比如某些严格的 Azure 网关要求显式 x-ms-version,用 with_headers 加进去即可,它会同时作用于 HEAD 和 range GET

⚠️ 稳定 URL 规则(并发下载必读)

StandardRangeDownload每一个并发分片都复用同一个固定 URLtask.url()),并且没有 URL 刷新机制。所以:

用于并发下载的预签名 / SAS URL,必须在整个传输(含续传)期间都保持有效。 签发时把有效期设得足够长,覆盖整个下载过程。

(预签名 URL 的自动刷新机制 PresignedDownloadUrlRefresher 只在串行PresignedRangeDownload 路径上生效,而并发下载走的不是那条路径。)

别把两个 with_total_size 搞混

  • DownloadPounceBuilder::with_total_size(total) —— 任务构建器上的方法,就是上面开启并发用的这个。
  • PresignedRangeDownloadPlan::with_total_size(total) —— plan 上的方法,供串行PresignedRangeDownload 协议使用,不会开启并发。

并发下载请用构建器上的那个 + 默认下载器。


7. 下载云存储对象(OSS / Azure)的两种姿势

姿势一(推荐,可并发):默认下载器 + 签名 URL

让你的后端签发一个 OSS 预签名 GET URL 或 Azure SAS URL,然后直接用第 6 节的 download_concurrent。这样既能并发、又不需要在客户端放任何密钥。这是绝大多数场景的首选。

姿势二(串行):provider 专属下载协议

如果你的程序运行在可信服务器上、且想直接用 AccessKey / Shared Key 签名,可以挂 provider 下载协议。注意这些协议只能串行with_max_parts_in_flight 对它们无效)。每种云的串行下载完整代码放在对应的实战文章里:

串行下载方式Feature完整代码
阿里云 OSS 直下(AliOssDirectDownload,AccessKey)aliyun-oss-direct阿里云 OSS 直传直下 · 下载方式一
阿里云 OSS 预签名 range 下载(PresignedRangeDownloadaliyun-oss-presigned阿里云 OSS 预签名 · 下载方式一
Azure Blob 直下(AzureBlobDirectDownload,Shared Key)azure-blob-directAzure Blob 直传直下 · 下载方式一
Azure Blob SAS range 下载(PresignedRangeDownloadazure-blob-sasAzure Blob SAS · 下载方式一

共同套路是:构建对应的 provider 下载协议 → with_breakpoint_download(Arc::new(协议))build()最小上手片段(以 OSS 直下为例):

let protocol = AliOssDirectDownload::new("my-bucket", "AK_ID", "AK_SECRET", "cn-beijing");
let task = DownloadPounceBuilder::new("obj.bin", "./downloads/obj.bin", 1024 * 1024, object_url)
    .with_breakpoint_download(Arc::new(protocol)) // 挂 provider 协议 = 串行
    .build();

想让上面这些 OSS / Azure 对象并发下载? 别用这一节的 provider 协议,改回第 6 节:让后端签一个 GET URL,用默认下载器 + with_total_size + with_max_parts_in_flight(4)。各云怎么签 URL 见对应实战文章的「下载方式二(推荐,可并发)」。


8. 并发下载的断点续传:.rcdl 边车文件

串行下载和并发下载的续传机制不一样

  • 串行下载文件长度续传:SDK 看到本地半成品文件有 X 字节,就请求 bytes=X-。不需要边车文件。
  • 并发下载把分片乱序写进一个预先撑到最终大小的文件,光看文件长度已经无法判断哪些分片下好了。于是它在目标文件旁边维护一个 <目标文件>.rcdl(resumable download log)边车文件:一张「哪些固定大小、按块对齐的分片已经稳妥落盘」的位图。

🖼️ 【配图占位 D2|.rcdl 边车续传】 建议配图:分三格时间轴。①第一次运行:预撑好的文件被分片写入,.rcdl 位图记录「分片 0/2/3 已落盘、分片 1 缺失」,此时进程被杀。②第二次运行:读 .rcdl,只重新拉取缺失的分片 1(已完成分片短路、不发网络请求)。③成功完成:校验文件长度 = total、所有分片齐全后,删除 .rcdl。图注:.rcdl 故意在取消/失败后保留,只有成功才删。 临时 ASCII 草图:

1次运行   文件[#0✅][#1⬜][#2✅][#3✅]   .rcdl 位图: 1011   ← 进程被杀,.rcdl 保留
第2次运行   只补 #1Range GET─▶            #0/#2/#3 短路不下载
成功完成    校验长度=total & 分片齐全 ──▶ 删除 .rcdl

边车什么时候会被复用 vs 丢弃

下次运行时,只有以下每一项都匹配,边车才会被信任、只补下缺失的分片:

绑定项必须一致
Range URL 身份同一个 URL(对其做 FNV-1a 哈希,含 host/port/path/query)
total同样的总大小
chunk同样的分片大小
max_parts同样的 with_max_parts_in_flight
目标文件其磁盘长度已经等于 total(是预撑好的,没被截断 / 删除)

只要任何一项变了(换了 URL、对象被重新生成、改了分片大小、改了 max_parts、目标文件被删/截断),旧边车就会被忽略,重新完整下载一遍。所以一个残留的 .rcdl 最坏也只会导致一次安全的重下,绝不会造成数据损坏

生命周期

  • 边车文件故意在取消 / 失败后保留,好让下次运行接着补下缺失分片(已下好的分片会直接短路、不发网络请求);
  • 只有在成功完成后才会被删除(SDK 会先校验文件长度等于 total、每个分片都在)。
  • 一次性、绝不续传的调用方,可以自己手动删掉它。

跨模式保护:如果目标文件旁边存在 .rcdl串行下载路径会拒绝运行并返回 InvalidTaskState。一个被中断的并发下载不能用串行方式接着下——要么继续用 with_max_parts_in_flight(n)n > 1)续传,要么把边车和半成品文件都删掉、从头开始。

进程重启后如何续传

和上传一样,rusty-cat 不内置数据库,续传要靠你在自己的库里持久化任务信息,重启后重建同一个 PounceTasktry_enqueue。对下载来说:

  1. 持久化:本地路径、下载 URL、分片大小、max_parts_in_flight、总大小等;
  2. 重启后查出未完成的任务、重建 DownloadPounceBuilder这五项要和上次完全一致,否则 .rcdl 会被判失效而重下);
  3. 再次 try_enqueue,并发下载会自动读 .rcdl、只补缺失分片。

9. 进度、暂停、恢复、取消

try_enqueue 拿细粒度回调 + TaskId

enqueue_and_wait 适合「提交后等到结束」。要做 UI、后台异步跑,用 try_enqueue,它返回 TaskId

use rusty_cat::api::{
    DownloadPounceBuilder, FileTransferRecord, MeowClient, MeowConfig, TaskId, TransferStatus,
};

async fn download_with_callbacks(
    url: &str,
    total: u64,
) -> Result<TaskId, Box<dyn std::error::Error + Send + Sync>> {
    let client = MeowClient::new(MeowConfig::default());
    let task = DownloadPounceBuilder::new("f.bin", "./downloads/f.bin", 1024 * 1024, url)
        .with_total_size(total)
        .with_max_parts_in_flight(4)
        .with_client_file_sign("business-file-id-001") // 可选:把业务主键塞进进度记录
        .build();

    let task_id = client
        .try_enqueue(
            task,
            // 进度回调
            move |record: FileTransferRecord| match record.status() {
                TransferStatus::Failed(err) => eprintln!("下载失败:{err}"),
                TransferStatus::Canceled => println!("已取消"),
                _ => println!("进度 {:.1}%", record.progress() * 100.0),
            },
            // 完成回调(下载的 payload 通常是 None)
            move |task_id, _payload| println!("任务 {task_id} 下载完成"),
        )
        .await?;

    Ok(task_id)
}

拿到 TaskId 就能控制任务:

client.pause(task_id).await?;   // 暂停
client.resume(task_id).await?;  // 从断点继续(TaskId 不变)
client.cancel(task_id).await?;  // 取消

并发下的进度行为(和上传一致)

即便分片乱序完成,SDK 只上报「最长连续前缀」的进度(水位线):

  • 进度单调递增,绝不回退;
  • 靠后的分片先下完、但前面有空洞时,进度会原地不动,直到空洞填上——是正常现象,不是卡死;
  • 每次水位线推进只收到一次合并后的进度事件,终态只有一次。

with_client_file_sign(...) 可以把你的业务主键放进 FileTransferRecord,回调里用 record.file_sign() 读出来,方便和数据库对应。


10. 内存占用与参数怎么选

每个在途 range 分片都需要一个缓冲区:

单个文件的峰值下载内存 ≈ n × 分片大小(上限,实际通常更低,因为响应体是边收边写进预撑好的文件的)

整个客户端要对同时在下的文件求和:

客户端峰值内存  ≈  max_download_concurrency × 下载 n × 下载分片大小
              +  max_upload_concurrency   × 上传 n × 上传分片大小

没有全局内存上限,请自己控制。实用建议:

  • 分片大小保持 1–8 MiB。太小请求开销大;太大每次重试要重下更多、且抬高内存下限。
  • n 从 4 开始试,仅在大文件 + 快网时用。带宽跑满后再加 n 收益很小、内存却翻倍。
  • 别忘了乘文件级并发:4 个文件 × n=8 × 4 MiB = 最多 128 MiB 缓冲。

11. 错误处理与自动重试

大多数调用返回 Result<_, MeowError>。用 MeowError::code()(稳定 i32 数字码)做分支,用 MeowError::msg() 打日志。不要匹配错误文本

下载常见错误码:

名称什么时候发生
102ParameterEmpty必填项(URL、文件名)为空
103DuplicateTaskError同一个 URL 的下载任务已经在排队 / 运行 / 暂停
107ClientClosed客户端已关闭,请新建 MeowClient
111CommandSendFailed命令队列满(快速失败),退避重试或调大 command_queue_capacity
117InvalidTaskState状态不允许该操作(如目标旁有 .rcdl 却走串行、或 resume 一个非暂停任务)
120TaskCanceled完成前被取消
121DiskFull写下载文件时磁盘满
122LocalFileRemoved传输中本地目标文件被删

还有两个下载特有的「硬错误」,它们快速失败、不重试(因为重试也没用):

  • InvalidRange:服务端对 Range 返回了 200 OK(无视 range),或 Content-Range 的起始 / 总大小对不上。→ 换一个真正支持 206 Partial Content 的端点。
  • MissingOrInvalidContentLengthFromHead:开了并发但总大小拿不到(没给 with_total_sizeHEAD 又没返回正数 Content-Length)。→ 显式 with_total_size(...)

自动重试

  • with_max_chunk_retries(n):单个 range 分片首次失败后额外重试的次数(默认 30 关闭),串行 / 并发路径都是按「每片」计
  • 预算内只重试瞬时错误(连接重置、超时、消息不完整、HTTP 408/429/5xx),并用指数退避(基准 200ms、上限 5000ms)+ ±20% 抖动等待。硬错误(如 403InvalidRange)快速失败,不消耗预算。

12. 常见问题排查表(FAQ)

现象可能原因解决
设了 n > 1 但还是串行三个前置条件没满足确认 n > 1、用默认下载器、且总大小已知(with_total_size
OSS / Azure 对象无法并发挂了 provider 下载协议(只能串行)去掉 with_breakpoint_download(...),用默认下载器 + 签名 GET URL
任务准备阶段直接失败开了并发但总大小拿不到显式 with_total_size(...),或改用能返回 Content-Length 的端点
分片报 InvalidRange服务端对 Range 回了 200(无视 range)指向真正支持 206 Partial Content 的端点
进度卡住然后突然跳靠后分片先下完、前面有空洞正常现象,进度按连续前缀单调推进,不是卡死
串行重下报 InvalidTaskState目标旁残留了上次并发中断的 .rcdl继续用 with_max_parts_in_flight(n) 续传,或删掉 .rcdl 和半成品文件重来
续传却从头下URL / total / chunk / max_parts / 目标文件长度和上次不一致这五项保持稳定,否则接受完整重下
签名 URL 传输中途失效并发下载复用一个 URL、无刷新签发时把有效期设得覆盖整个下载(含续传)
入队大量任务报 CommandSendFailed命令队列满(try_enqueue 快速失败)调大 command_queue_capacity 或自己退避重试

13. 附录:配置项速查表

DownloadPounceBuilder(下载任务)

方法必填?说明
new(file_name, file_path, chunk_size, url)创建 range 下载任务;chunk_size == 0 归一化为默认 1 MiB
with_total_size(size)并发要已知总大小,跳过 HEAD开启并发下载的关键
with_max_parts_in_flight(n)可选单文件 range 分片并发数,默认 1;仅默认下载器 + 总大小已知时生效
with_max_chunk_retries(n)可选单片重试次数,默认 3
with_url(url)可选替换下载 URL
with_file_path(path)可选替换本地保存路径
with_headers(headers)可选替换 HEAD 和 range GET 的基础请求头(加 provider 头用这个)
with_client_file_sign(sign)可选把业务主键塞进进度记录,回调里用 file_sign()
with_breakpoint_download(Arc::new(...))可选挂 provider / 自定义下载协议(会变串行
with_breakpoint_download_http(cfg)可选单任务覆盖 range 下载的 Accept
build()返回 PounceTask(无错误,校验发生在入队 / 运行时)

MeowConfig(客户端级配置)

参数默认约束说明
max_download_concurrency2>= 1同时下载的文件数
max_upload_concurrency2>= 1同时上传的文件数
http_timeout5s正数单请求超时
tcp_keepalive30s正数TCP keepalive
command_queue_capacity128>= 1命令队列容量
worker_event_queue_capacity256>= 1事件队列容量
breakpoint_download_http.range_acceptapplication/octet-stream合法头值range 下载默认 Accept

MeowClient(客户端)常用方法

方法用途
MeowClient::new(config)创建客户端(执行器懒启动)
enqueue_and_wait(task, progress_cb).await提交并等到终态,返回 TaskOutcome
try_enqueue(task, progress_cb, complete_cb).await提交任务,返回 TaskId(快速失败,不等完成)
try_enqueue_paused(task, ..).await以暂停态导入,不做任何 IO,之后 resume 才启动
pause / resume / cancel (task_id).await暂停 / 恢复 / 取消
register_global_progress_listener(cb)注册观测「所有任务」进度的全局监听器
snapshot().await查看排队 / 活跃的任务组数量
close().await关机必调:优雅关闭

相关阅读

本文基于 rusty-cat 0.2.4 编写,所有代码片段均经过 cargo check 编译验证。