首页 / 博客 / Suno API 批量生成:并发、队列、重试与去重
API

Suno API 批量生成:并发、队列、重试与去重

用 Suno API 批量生成音乐时如何控制并发、保存 request_id、使用幂等键、处理 429 和失败恢复,附可运行的队列示例与容量估算。

多个音乐生成任务在受控队列中并行处理

图:Pexels

直接答案:批量生成不要开无限线程。每个业务任务使用唯一 Idempotency-Key,调用创建接口时加 accept_mode=async,把 request_id 落库,再用固定大小的 worker 队列轮询受理进度。单 Key 的并发生成上限通常是 5,超过会触发限流或排队。

批量系统的四个对象

对象示例作用
业务批次batch_20261027_a一组要一起交付的音乐
业务任务brief_001一个提示词或一首业务歌单条目
生成受理request_id一次创建请求的异步回执
歌曲song_id真正可查询、下载的媒体对象

先排队,再并发

最简单的实现是“生产者 + 固定 worker 池”:业务只负责把任务写入队列,worker 从队列取任务并提交 API。不要为每一行 CSV 直接创建一个无限线程,否则几分钟内就会触发 429。

  • 生成并发:先按 3–4 个 worker 起步,确认实际账号额度后再接近 5。
  • 轮询并发:和生成职责分开,避免大量轮询占用生成 worker。
  • 批量查询:可把多个 song_id 用英文逗号拼接,一次查询多首。
  • 队列容量:按业务高峰和目标完成时延计算,不靠提高并发硬顶。

Python worker 池示例

import concurrent.futures
import time
import uuid
import requests

BASE = "https://www.suno-api.io"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}


def submit_one(brief):
    headers = {
        **HEADERS,
        "Content-Type": "application/json",
        "Idempotency-Key": brief["idempotency_key"],
    }
    response = requests.post(
        f"{BASE}/api/music/create",
        headers=headers,
        json={
            "description": brief["description"],
            "model": "suno-v6",
            "accept_mode": "async",
        },
        timeout=60,
    )
    response.raise_for_status()
    data = response.json()["data"]
    return {
        "brief_id": brief["brief_id"],
        "request_id": data["request_id"],
        "status": data["status"],
    }


briefs = [
    {
        "brief_id": f"brief_{i:03d}",
        "idempotency_key": f"batch-20261027-{i:03d}",
        "description": f"第 {i} 条短剧配乐,悬疑,弦乐,无人声",
    }
    for i in range(1, 21)
]

with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool:
    accepted = list(pool.map(submit_one, briefs))

print("accepted", len(accepted))

这段代码只负责受理,不负责等待。生产系统应把 accepted 写入数据库,再由独立轮询 worker 继续处理。这样进程重启不会丢任务,也不会重复创建。

轮询受理进度

def refresh_request(request_id):
    response = requests.get(
        f"{BASE}/api/music/requests/{request_id}",
        headers=HEADERS,
        timeout=60,
    )
    response.raise_for_status()
    data = response.json()["data"]

    for task in data.get("tasks", []):
        if task.get("song_id"):
            save_song(
                request_id=request_id,
                task_index=task["index"],
                song_id=task["song_id"],
                status=task["status"],
            )

    return data["status"]

partial 时先保存已经完成的任务;failed 时标记失败并停止该 request_id;只有明确失败才按规则决定是否创建新业务任务。

重试表

情况是否重试做法
400 参数错误否修数据,不能原样重试
401 / 403否修 Key 或账号状态
402 余额不足否充值后恢复队列
429 限流是读 retry_after,降低并发并退避
5xx 暂时异常是指数退避,复用幂等键
创建请求超时先查后重试先查受理记录或歌曲历史,确认不存在再提交

容量估算

假设 100 个业务条目、每个条目提交一次生成、每次返回 2 首歌,那么会产生 100 个生成受理和最多 200 首歌。真正限制吞吐的通常是生成并发和上游完成时间,而不是轮询请求本身。先根据“同时生成数 × 平均完成时间”估算交付时间,再决定是否扩账号或拆批次。

常见问题

一单返回两首,算几个并发?

并发按生成请求数计算。一次请求就是一个生成任务,即使它返回两条歌曲结果。

遇到 429 可以立即重试吗?

不可以。先等待 retry_after,降低 worker 数量,再用同一个 Idempotency-Key 重放不确定结果的请求。

进程重启后怎么恢复任务?

从数据库读取 request_id 和 song_id 继续查询。不要依赖内存中的任务列表,也不要重新提交已受理的业务任务。

相关页面:cURL 与 Postman、返回字段详解、鉴权与限流、受理回执模式。

0.6 元一次,固定出 2 首,下载不限次

官方原版 Suno 引擎,支持最新 V6,MP3 与 WAV 均可下载。注册不需要手机号。