bash wait -n fails on macOS bash 3.2: cap curl jobs at four

On macOS /bin/bash 3.2 'wait -n' is an invalid option, so a throttled curl loop spins. A portable version that caps Sume video submits at four in flight.

4 min readSume
All posts

The standard recipe for 'run these curl calls, but only four at a time' in bash is a loop that checks jobs -rp | wc -l and calls wait -n when the pool is full. wait -n (wait for any one job) arrived in Bash 4.3. The /bin/bash that macOS ships is 3.2.57, and there the same line prints wait: -n: invalid option and returns 2. Inside a loop that means the throttle never blocks: it spins or, with set -e, kills the script.

The version below falls back to a short sleep when wait -n is not available, so the same file works on Bash 3.2 and on 4.3 or later. It posts 12 five-second Wan 3.0 clips at 480p to POST /v1/videos, keeps at most four requests in flight, and gives each shot its own Idempotency-Key. It was run on bash 3.2.57 against a local stand-in server, not the live API.

The script (16 lines)

curl -w '%{http_code}' prints the status after the body goes to a file, so the log line is one short string per shot. Set SUME_BASE and SUME_API_KEY before running.

#!/usr/bin/env bash
set -u
: "${SUME_API_KEY:?set SUME_API_KEY}"
MAX=4
submit() {  # $1 = shot number
  code=$(curl -s -o "out-$1.json" -w '%{http_code}' -X POST "$SUME_BASE/v1/videos" \
    -H "x-api-key: $SUME_API_KEY" -H 'content-type: application/json' \
    -H "Idempotency-Key: trailer-v3-shot-$1" \
    -d "{\"model\":\"wan-3.0\",\"prompt\":\"shot $1\",\"duration\":5,\"resolution\":\"480p\"}")
  echo "shot $1 -> $code"
}
for i in $(seq -w 1 12); do
  while [ "$(jobs -rp | wc -l)" -ge "$MAX" ]; do wait -n 2>/dev/null || sleep 0.2; done
  submit "$i" &
done
wait

Why not xargs or GNU parallel

xargs -P is the better tool when your input is a file of prompts (see the related xargs post). A loop like this one earns its place when each job needs a different key, a different body or a log line of its own. GNU parallel is not installed by default on macOS or most CI images, which is the other reason to keep to builtins.

After the loop

Each out-NN.json holds a 202 body with the job id and polling_url. A non-202 code in the log is the cue to rerun just that shot with the same key. The throttle is client-side pacing: Sume itself accepts queued work up to your plan's accepted capacity (24 jobs on Pro) before it answers 429 queue_full.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume