Queue and result storage

Studio, the music/speech APIs, MCP and optional native tools share one serial compute worker. There is no parallel GPU inference.

Capacity and retrying

The default limit is eight accepted jobs, including the active job. Set YUE2_QUEUE_LIMIT at startup to change it (1–128). All generation routes use the same atomic admission check. MCP additionally retains its eight-song limit. Queued cancellation removes that job immediately and releases its slot. Active cancellation uses the existing engine checkpoints.

Native and compatibility routes refuse excess work with HTTP 429 and Retry-After: 5. Native errors also include code and retry_after_seconds; compatibility errors retain the OpenAI error envelope. MCP returns an isError: true tool result with structured code: queue_full and retry_after_seconds: 5, plus the response header; it keeps normal JSON-RPC transport framing.

Wait at least the indicated interval before retrying a refused submission. Add jitter and increase the delay on repeated refusals, for example 5, 10, 20 and 30 seconds. A refused submission has not created a job. After acceptance, poll the returned job instead of submitting the song again. An interrupted connection can leave an ambiguous outcome; do not blindly replay an expensive request.

Status and System

GET /health, GET /status and GET /system/queue return the same uncached snapshot. Health remains HTTP 200 while the queue is full: saturation does not mean the process needs restarting.

{
  "status": "ok",
  "queue": {
    "limit": 8, "pending": 3, "active": 1, "queued": 2,
    "available": 5, "accepting": true, "retry_after_seconds": 5,
    "rejected": 0, "completed": 4, "failed": 0, "cancelled": 0,
    "active_operation": "synth"
  },
  "results": {
    "location": "volume", "files": 4, "bytes": 2500000,
    "limit_bytes": 10737418240, "limit_files": 256,
    "max_file_bytes": 1073741824, "ttl_seconds": 86400, "full": false
  },
  "http": {
    "workers": 20, "synchronous_limit": 8, "synchronous_waiters": 0,
    "download_limit": 4, "log_stream_limit": 2, "upload_decoder_limit": 2,
    "max_upload_bytes": 67108864
  }
}

Counters reset on process restart. Completed result metadata and expiry survive on the output volume. Snapshots contain aggregate operations, never other callers’ job handles, prompts or lyrics. GET /props also advertises the queue configuration.

Native GET /job?id=ID now distinguishes queued, running, done, failed and cancelled, with queue_position (one-based while waiting, zero otherwise). Completed stored jobs include expires_at and existing generation metrics. Older clients that only recognize running as pending must also accept queued. MCP keeps its existing queued / generating / complete states and adds queue position to pending status.

The System tab shows capacity, pending/active counts, rejections and native result volume usage. Polling runs only while that tab and the document are visible.

Completed results live on the output volume

Mount /output when running the container:

docker volume create yue2-output

Add --mount type=volume,source=yue2-output,target=/output to docker run. task start already mounts data/results/studio/ there. Custom bind mounts must be writable by UID 10001. Without a mount, files live in the container’s writable layer and disappear when that container is removed.

Native/Studio results are stored under /output/jobs/: the exact response body and a small metadata sidecar. This includes audio, multipart replay/latents, transcription and VAE results. Synchronous API audio is stored once and served from that same file. MCP writes its single selected export directly to /output/agent-artifacts/, with its existing one-hour capability expiry.

Native result defaults are 24 hours, 10 GiB total, 256 files, and 1 GiB per result. Configure these restart-required environment variables:

Variable Default Supported values
YUE2_QUEUE_LIMIT 8 1–128 accepted jobs, including active work
YUE2_RESULT_DIR jobs relative to the working directory Writable native result directory; mount it persistently
YUE2_RESULT_TTL_SECONDS 86400 1–2592000 seconds; fixed from completion
YUE2_RESULT_MAX_BYTES 10737418240 1 byte–1 TiB total native results
YUE2_RESULT_MAX_FILES 256 1–10000 retained native results

Live results are never evicted early to make space. An already-full store refuses new native/API submissions with HTTP 507. A result exceeding the remaining budget, the per-file limit, or available disk space fails publication cleanly; it is not reported complete. Lowering limits preserves existing live results and blocks new ones until enough space becomes available. MCP’s separate 128-file / 2-GiB store and one-hour links are unchanged.

Expiry is checked on every lookup. Cleanup runs every 30 seconds, before result publication and at startup. An already-open native download retains a file lease until delivery ends. Interrupted staging files are removed on restart; unrelated files are left alone. Job handles retain their original expiry across restarts. Queued/running work is process-local and is not replayed after a restart.

The server keeps only small job/result metadata in its index. Current inference, encoding, queued input data and HTTP upload parsing still require working RAM; completed audio and multipart bodies are streamed from disk in bounded chunks. The browser’s IndexedDB library is separate and remains unchanged. Save downloads elsewhere for permanent archiving; this volume is a bounded result cache.

Generation’s pipeline_seconds remains the model-work metric. The worker’s encoding_packaging_seconds and worker_seconds include result-body serialization to disk; HTTP delivery and client parsing remain separate. Existing historical benchmark reports are unchanged.

Responsiveness and tests

The HTTP server uses 20 fixed workers, at most eight synchronous generation requests (including their downloads), four additional native/MCP result downloads, two upload decoders and two log streams. This leaves capacity for ordinary health, polling and cancellation requests. Payloads are limited to 64 MiB and socket read/write timeouts are 15 seconds. Synchronous generation deadlines still include queue time (600 seconds by default).

task check:cpu compiles the model-free server-check fixture and runs tests/server/check_runtime.py. It tests shared admission, cancellation, exception recovery, slow writes, storage budgets/expiry, byte ranges, restarts, eight held synchronous handlers and a burst of 32 refused requests while probing health. The fixture uses the production queue, storage and HTTP primitives with an artificial worker; it does not measure model speed or musical quality.

task test:api checks the deployed read-only snapshots. Real packaged CUDA/UI generation is a separate qualification.