Skip to content

[BUG] 通过 API 调用 115 Open 离线下载时,POST /api/fs/add_offline_download 被内部重复执行并以 10008 失败但实际成功 #2954

Description

@Solr159

请确认以下事项

  • 我已确认阅读并同意 AGPL-3.0 第15条
    本程序不提供任何明示或暗示的担保,使用风险由您自行承担。

  • 我已确认阅读并同意 AGPL-3.0 第16条
    无论何种情况,版权持有人或其他分发者均不对使用本程序所造成的任何损失承担责任。

  • 我确认我的描述清晰,语法礼貌,能帮助开发者快速定位问题,并符合社区规则。

  • 我已确认阅读了OpenList文档

  • 我已确认没有重复的问题或讨论。

  • 我已确认是OpenList的问题,而不是其他原因(例如 网络依赖操作)。

  • 我认为此问题必须由OpenList处理,而非第三方。

  • 我已确认这个问题在最新版本中没有被修复。

  • 我没有阅读这个清单,只是闭眼选中了所有的复选框,请关闭这个 Issue 。

OpenList 版本(必填)

v4.2.5

使用的存储驱动(必填)

115 Open

问题描述(必填)

复现步骤

1. 配置 115 Open

按照官方文档配置好115 Open和临时目录

2. 提交一个全新的磁力链接

客户端只调用一次 OpenList 接口:

POST /api/fs/add_offline_download
Authorization: <OPENLIST_TOKEN>
Content-Type: application/json
Accept: application/json

请求体:

{
  "urls": [
    "magnet:?xt=urn:btih:<REDACTED_NEW_INFO_HASH>"
  ],
  "path": "/115-open/<TARGET_DIRECTORY>",
  "tool": "115 Open",
  "delete_policy": "delete_never"
}

等效 curl:

curl -X POST 'http://127.0.0.1:5244/api/fs/add_offline_download' \
  -H 'Authorization: <OPENLIST_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  --data-raw '{
    "urls": ["magnet:?xt=urn:btih:<REDACTED_NEW_INFO_HASH>"],
    "path": "/115-open/<TARGET_DIRECTORY>",
    "tool": "115 Open",
    "delete_policy": "delete_never"
  }'

3. 查询 OpenList 任务状态

客户端轮询:

POST /api/task/offline_download/info?tid=<OPENLIST_TASK_ID>
Authorization: <OPENLIST_TOKEN>
Accept: application/json

等效 curl:

curl -X POST \
  'http://127.0.0.1:5244/api/task/offline_download/info?tid=<OPENLIST_TASK_ID>' \
  -H 'Authorization: <OPENLIST_TOKEN>' \
  -H 'Accept: application/json'

任务最终返回:

{
  "code": 200,
  "data": {
    "id": "<OPENLIST_TASK_ID>",
    "state": 7,
    "error": "failed to add offline download task: code: 10008, message: 任务已存在,请勿输入重复的链接地址。"
  }
}

tache.StateFailed 的值为 7

4. 在 Openlist 中检查状态

Openlist 首页目录中已经能看到离线任务下载成功
Openlist '管理' -> '任务' -> '离线下载'->'已完成' 中查看,此任务状态显示失败:"错误
failed to add offline download task: code: 10008, message: 任务已存在,请勿输入重复的链接地址。"

日志(必填)

failed to add offline download task: code: 10008, message: 任务已存在,请勿输入重复的链接地址

配置文件内容(必填)

{
"force": false,
"site_url": "",
"cdn": "",
"jwt_secret": "vuUo6WOuKnHqpX1i",
"token_expires_in": 48,
"database": {
"type": "sqlite3",
"host": "",
"port": 0,
"user": "",
"password": "",
"name": "",
"db_file": "data/data.db",
"table_prefix": "x_",
"ssl_mode": "",
"dsn": ""
},
"meilisearch": {
"host": "http://localhost:7700",
"api_key": "",
"index": "openlist"
},
"scheme": {
"address": "0.0.0.0",
"http_port": 5244,
"https_port": -1,
"force_https": false,
"cert_file": "",
"key_file": "",
"unix_file": "",
"unix_file_perm": "",
"enable_h2c": false,
"enable_h3": false
},
"temp_dir": "data/temp",
"bleve_dir": "data/bleve",
"dist_dir": "",
"log": {
"enable": true,
"name": "data/log/log.log",
"max_size": 50,
"max_backups": 30,
"max_age": 28,
"compress": false,
"filter": {
"enable": false,
"filters": [
{
"cidr": "",
"path": "/ping",
"method": ""
},
{
"cidr": "",
"path": "",
"method": "HEAD"
},
{
"cidr": "",
"path": "/dav/",
"method": "PROPFIND"
}
]
}
},
"delayed_start": 0,
"auto_memory_limit": 4,
"min_free_memory": 0,
"max_block_limit": 0,
"max_connections": 0,
"max_concurrency": 64,
"tls_insecure_skip_verify": false,
"tasks": {
"download": {
"workers": 5,
"max_retry": 1,
"task_persistant": false
},
"transfer": {
"workers": 5,
"max_retry": 2,
"task_persistant": false
},
"upload": {
"workers": 5,
"max_retry": 0,
"task_persistant": false
},
"copy": {
"workers": 5,
"max_retry": 2,
"task_persistant": false
},
"move": {
"workers": 5,
"max_retry": 2,
"task_persistant": false
},
"decompress": {
"workers": 5,
"max_retry": 2,
"task_persistant": false
},
"decompress_upload": {
"workers": 5,
"max_retry": 2,
"task_persistant": false
},
"allow_retry_canceled": false
},
"cors": {
"allow_origins": [
""
],
"allow_methods": [
"
"
],
"allow_headers": [
"*"
]
},
"s3": {
"enable": false,
"port": 5246,
"ssl": false
},
"ftp": {
"enable": false,
"listen": ":5221",
"find_pasv_port_attempts": 50,
"active_transfer_port_non_20": false,
"idle_timeout": 900,
"connection_timeout": 30,
"disable_active_mode": false,
"default_transfer_binary": false,
"enable_active_conn_ip_check": true,
"enable_pasv_conn_ip_check": true
},
"sftp": {
"enable": false,
"listen": ":5222"
},
"mcp": {
"enable": false
},
"last_launched_version": "v4.2.5",
"proxy_address": ""
}

复现链接(可选)

No response

AI生成内容(可选)

根因已经定位到一个非常具体的 OpenList 4.2.5 代码缺陷,不是你的应用重复调用:115 首次添加成功后,OpenList 立刻查任务列表;当
115 的列表暂时还没同步到新任务时,OpenList 本应返回“尚未找到”,但代码实际返回了 (nil, nil)。随后状态更新解引用空对象,任务执
行器重跑整个任务,于是第二次提交同一磁力,115 才返回 10008。

实际调用链是:

  1. 你的应用只向 OpenList 提交一次离线下载任务。

  2. OpenList 调用 115 SDK,115 成功创建离线任务。SDK 本身只发一次添加请求,也不会因为 10008 自动重试。115 SDK 源码
    (https://github.com/OpenListTeam/115-sdk-go/blob/v0.2.6/offline.go)

  3. OpenList 约 3 秒后查询任务状态。

  4. 如果 115 的任务列表暂时还没同步出新任务,OpenList 的 Status 实现错误地返回了 (nil, nil)。OpenList 115 Open 实现
    (https://github.com/OpenListTeam/OpenList/blob/v4.2.5/internal/offline_download/115_open/client.go#L88)

  5. OpenList 随后解引用空的状态对象,引发 panic。状态更新代码
    (https://github.com/OpenListTeam/OpenList/blob/v4.2.5/internal/offline_download/tool/download.go#L142)

  6. OpenList 使用的任务框架捕获 panic,并按默认 MaxRetry: 1 重新执行整个任务。任务配置
    (https://github.com/OpenListTeam/OpenList/blob/v4.2.5/internal/conf/config.go#L179)

  7. 重新执行会再次调用添加接口,于是 115 返回:

    10008:任务已存在

这也完整解释了现象:

  • 为什么所有新链接第一次都会报重复;
  • 为什么 115 实际已经开始或完成离线下载;
  • 为什么 OpenList 里任务显示失败;
  • 为什么最终仍然能够找到文件并下载;
  • 为什么部分 OpenList 失败记录耗时只有零点几秒:第一次执行约 3 秒后 panic,第二次重试重新记录开始时间,并立刻收到 10008。

而且 OpenList 当前 main 分支仍然保留这个问题,所以单纯升级目前未必能解决。当前源码
(https://github.com/OpenListTeam/OpenList/blob/main/internal/offline_download/115_open/client.go#L88)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions