Swift withTaskGroup: four Sume video submits in flight
A sliding window in Swift 6: withTaskGroup keeps four POST /v1/videos requests in flight, re-arming as each finishes. One file, URLSession, no packages.

Swift concurrency makes a bounded fan-out compact. Start a task group with four child tasks, and every time one finishes (group.next()) add the next shot. That sliding window keeps exactly four submits in flight with no semaphore.
The file below posts 12 five-second Wan 3.0 clips at 480p. It ran as a single-file script with swift fan.swift on Swift 6.3.2 against a local stand-in server that answers 202; it was not pointed at the live API. Set SUME_BASE and SUME_API_KEY in the environment first.
The code (23 lines)
Each task returns (shot, statusCode), so the sorted output at the end is in shot order even though tasks finish in any order. A transport error returns 0. The per-shot Idempotency-Key means a rerun replays any job Sume already accepted.
import Foundation
func submit(_ i: Int) async -> Int {
var req = URLRequest(url: URL(string: ProcessInfo.processInfo.environment["SUME_BASE"]! + "/v1/videos")!)
req.httpMethod = "POST"
req.setValue(ProcessInfo.processInfo.environment["SUME_API_KEY"]!, forHTTPHeaderField: "x-api-key")
req.setValue("application/json", forHTTPHeaderField: "content-type")
req.setValue(String(format: "trailer-v3-shot-%02d", i), forHTTPHeaderField: "Idempotency-Key")
req.httpBody = Data(#"{"model":"wan-3.0","prompt":"shot \#(i)","duration":5,"resolution":"480p"}"#.utf8)
guard let (_, res) = try? await URLSession.shared.data(for: req) else { return 0 }
return (res as? HTTPURLResponse)?.statusCode ?? 0
}
let codes = await withTaskGroup(of: (Int, Int).self) { group in
var next = 0, out: [(Int, Int)] = []
for _ in 0..<4 { group.addTask { [n = next] in (n, await submit(n)) }; next += 1 } // 4 in flight
while let done = await group.next() {
out.append(done)
if next < 12 { group.addTask { [n = next] in (n, await submit(n)) }; next += 1 }
}
return out.sorted { $0.0 < $1.0 }.map { $0.1 }
}
print(codes)Script mode versus an app target
Top-level await is allowed here because swift fan.swift runs the file as a script. Inside an app or a package you would wrap the same body in an async function and call it from your entry point. Compiling the same file with swiftc -parse-as-library rejects the top-level statements (expressions are not allowed at the top level).
Choosing the window
Four is the processing concurrency of a Pro workspace. Sume queues anything it cannot start, so the hard cap on submits is the accepted capacity (24 on Pro), after which a paid submit returns 429 queue_full. Treat the window as pacing, and read the live generation_limits from a submit response if you want to adapt it.
For polling after the submits, the related Swift post covers next_poll_after_seconds.
Sources
Related posts
More in Developers
- 10 hooks by 10 endings: a 100-variant grid in one Sume bulk queue
A 10 by 10 hook and ending grid is exactly 100 items, the bulk queue maximum. How to build the items array, pick concurrency up to 16, and read the result.
- A ten-photo edit regression suite to re-run when a model launches
Ten photos, five edits each, one scoring sheet: a cheap test to re-run whenever a new image edit model launches. 50 edits cost $1.875 at the low tier on Sume.
- How many video scenes fit in one Sume script_run? Ten
script_run allows at most 32 paid calls per run. At three paid calls per scene (voice, image, clip) that is ten scenes, with two calls to spare.
- Test a Sume webhook receiver with signed fixtures, no paid job needed
Generate sume-v1 signatures yourself and test six cases: good, rotated, reserialized, stale, empty-secret and unknown event. Python code that runs as is.
Written by Sume