feat: per-provider concurrency lanes (cloud parallel while local churns)
Build & push image / build-and-push (push) Successful in 7s
Build & push image / build-and-push (push) Successful in 7s
entrypoint.sh groups models by provider into lanes that run in PARALLEL; within
a lane at most `cap` models run at once. cap = GADFLY_PROVIDER_CONCURRENCY map
("ollama-cloud=3,m1pro=1") else GADFLY_CONCURRENCY (default 1). So a single
local box stays serial (1 at a time) while cloud models run several at once and
both lanes progress simultaneously. Portable bash (no associative arrays).
Default cap 1 keeps a single-provider pool sequential as before. Pairs with the
per-lens timeout so a slow lane can't starve others. Docs: README Concurrency
section + config table; CLAUDE.md lessons incl. the docker://:latest cache gotcha.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+61
-13
@@ -124,21 +124,69 @@ log "cloning ${REPO_PATH} @ ${BRANCH}"
|
||||
git clone --depth=1 --branch "$BRANCH" "$CLONE_URL" "$REPO_DIR" 2>/dev/null \
|
||||
|| die "clone of ${REPO_PATH}@${BRANCH} failed"
|
||||
|
||||
# --- review once per model -------------------------------------------------
|
||||
# GADFLY_MODELS is the provider-agnostic name; OLLAMA_REVIEW_MODELS is kept as a
|
||||
# --- review once per model, with per-provider concurrency -------------------
|
||||
# GADFLY_MODELS is the provider-agnostic name; OLLAMA_REVIEW_MODELS is a
|
||||
# back-compat alias. GADFLY_PROVIDER / GADFLY_BASE_URL / GADFLY_API_KEY and any
|
||||
# provider key envs (OPENAI_API_KEY, …) are inherited by run.sh and the binary.
|
||||
#
|
||||
# Concurrency: each PROVIDER is its own lane and lanes run in PARALLEL, so a fast
|
||||
# cloud provider isn't stuck behind a slow local box. Within a lane, at most
|
||||
# `cap` models run at once. cap = GADFLY_PROVIDER_CONCURRENCY's "provider=N"
|
||||
# entry, else GADFLY_CONCURRENCY (default 1). A model's provider is the spec's
|
||||
# first path segment ("m1pro/qwen3.6:35b-mlx" -> m1pro), or GADFLY_PROVIDER /
|
||||
# ollama-cloud for a bare id. Default (cap 1) keeps a single-provider pool fully
|
||||
# sequential, exactly as before.
|
||||
MODELS="${GADFLY_MODELS:-${OLLAMA_REVIEW_MODELS:-$DEFAULT_MODELS}}"
|
||||
log "provider: ${GADFLY_PROVIDER:-ollama-cloud}; models: ${MODELS}"
|
||||
IFS=',' read -ra ARR <<< "$MODELS" || true
|
||||
for raw in "${ARR[@]}"; do
|
||||
m="$(echo "$raw" | tr -d '[:space:]')"
|
||||
[ -z "$m" ] && continue
|
||||
log "::: reviewing with ${m}"
|
||||
PROVIDER=ollama \
|
||||
MODEL="$m" \
|
||||
GADFLY_BIN="/usr/local/bin/gadfly" \
|
||||
GADFLY_REPO_DIR="$REPO_DIR" \
|
||||
bash "${SCRIPTS_DIR}/run.sh" || log "model ${m} failed (continuing)"
|
||||
DEFAULT_CONC="${GADFLY_CONCURRENCY:-1}"
|
||||
|
||||
provider_of() { case "$1" in */*) echo "${1%%/*}";; *) echo "${GADFLY_PROVIDER:-ollama-cloud}";; esac; }
|
||||
|
||||
provider_cap() { # provider -> concurrency (override map "p=N,...", else default)
|
||||
local p="$1" item k v
|
||||
IFS=',' read -ra _caps <<< "${GADFLY_PROVIDER_CONCURRENCY:-}"
|
||||
for item in "${_caps[@]}"; do
|
||||
k="$(echo "${item%%=*}" | tr -d '[:space:]')"
|
||||
v="$(echo "${item#*=}" | tr -d '[:space:]')"
|
||||
if [ "$k" = "$p" ] && [ -n "$v" ]; then echo "$v"; return; fi
|
||||
done
|
||||
echo "$DEFAULT_CONC"
|
||||
}
|
||||
|
||||
review_one() {
|
||||
PROVIDER=ollama MODEL="$1" GADFLY_BIN="/usr/local/bin/gadfly" GADFLY_REPO_DIR="$REPO_DIR" \
|
||||
bash "${SCRIPTS_DIR}/run.sh" || log "model $1 failed (continuing)"
|
||||
}
|
||||
|
||||
# Normalize the model list (trim, drop blanks) into MODEL_LIST.
|
||||
IFS=',' read -ra _raw <<< "$MODELS" || true
|
||||
MODEL_LIST=()
|
||||
for raw in "${_raw[@]}"; do m="$(echo "$raw" | tr -d '[:space:]')"; [ -n "$m" ] && MODEL_LIST+=("$m"); done
|
||||
|
||||
# Distinct providers, in first-seen order (no associative arrays — portable).
|
||||
PROVIDERS=""
|
||||
for m in "${MODEL_LIST[@]}"; do
|
||||
p="$(provider_of "$m")"
|
||||
case " $PROVIDERS " in *" $p "*) ;; *) PROVIDERS="${PROVIDERS}${PROVIDERS:+ }$p" ;; esac
|
||||
done
|
||||
|
||||
run_lane() { # $1=provider: run its models, at most `cap` at a time
|
||||
local p="$1" cap inflight=0 m
|
||||
cap="$(provider_cap "$p")"; [ "$cap" -ge 1 ] 2>/dev/null || cap=1
|
||||
local mine=()
|
||||
for m in "${MODEL_LIST[@]}"; do [ "$(provider_of "$m")" = "$p" ] && mine+=("$m"); done
|
||||
log "lane ${p}: cap ${cap}; models: ${mine[*]}"
|
||||
for m in "${mine[@]}"; do
|
||||
review_one "$m" &
|
||||
inflight=$((inflight+1))
|
||||
if [ "$inflight" -ge "$cap" ]; then wait -n 2>/dev/null || wait; inflight=$((inflight-1)); fi
|
||||
done
|
||||
wait
|
||||
}
|
||||
|
||||
log "providers: ${PROVIDERS:-none}"
|
||||
# Each provider lane runs in parallel; cap is enforced within each lane.
|
||||
for p in $PROVIDERS; do
|
||||
run_lane "$p" &
|
||||
done
|
||||
wait
|
||||
log "done"
|
||||
|
||||
Reference in New Issue
Block a user