supersonic-interlink: scale from zero, and stop the Failed pods piling up - #246
Merged
Merged
Conversation
…g up SuperSONIC main (#90) no longer refuses scaleFromZero together with envoy.external_config.load_from_configmap; a custom configuration is now responsible for the clusters, Lua filter and routes the generated one would have added. So this release can hold no Slurm allocation while idle. envoy-config.yaml is rewritten as the configuration the chart generates plus the three things a Triton behind a Slurm-side wstunnel needs and the chart cannot express: a 32 MB request buffer, outlier ejection, and the retry policy on the inference route. From the generated side it gains the Lua filter, the triton_admission and envoy_admin clusters, the RepositoryIndex route, dns_refresh_rate 1s and connect_timeout 2s. The Lua filter is placed ahead of the buffer so a wake starts on the headers. readyTimeoutSeconds is 900, not the 300 the other releases use: waking here queues a Slurm job on Hammer and waits for it to start, rather than scheduling a pod. The route's idle_timeout follows at 1020s, the margin the chart applies. Both are guesses at Hammer's queue for one GPU and are the numbers to raise if RepositoryIndex starts timing out. The pruner is unrelated to scaling. When a Slurm job exits, the virtual kubelet marks the pod Failed instead of restarting the container in place, so the ReplicaSet makes a replacement and the corpse stays — one more every couple of minutes for as long as the job keeps failing, 22 of them while this was being written. Nothing sweeps them: PodGC only fires at the cluster-wide terminated-pod threshold and ttlSecondsAfterFinished is a Job field. A five-minute CronJob keeps the newest, for diagnosis, and deletes the rest. Verified: `envoy --mode validate` accepts the config against the rendered Lua filter (3 clusters, 1 listener); the pruner's pipeline was run read-only against the live namespace (22 failed, 21 selected, newest kept) and its sed/xargs checked inside alpine/kubectl, where an empty list is a no-op. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two independent changes to
supersonic-interlink.1. Failed Triton pods no longer accumulate
When the Slurm job exits, interLink's virtual kubelet marks the pod
Failedrather than restartingthe container in place (
restartCount: 0,terminated: exitCode 255). The ReplicaSet then createsa replacement and the corpse stays — one more every couple of minutes for as long as the job keeps
failing. There were 22 in the namespace while this was being written.
Nothing in Kubernetes sweeps them: PodGC only fires at the cluster-wide
terminated-pod-gc-threshold,and
ttlSecondsAfterFinishedis a Job field, not a Deployment one. So a five-minute CronJob keepsthe newest — worth having for diagnosis — and deletes the rest.
Run read-only against the live namespace: 22 failed, 21 selected, newest kept.
sed '$d'andxargs -rwere checked insidealpine/kubectl:1.34.1itself (busybox — notac, nohead -n -1),including that an empty list is a no-op and not an error.
2. Scale from zero
SuperSONIC main (#90) dropped the
scaleFromZero.enabled is incompatible with envoy.external_config.load_from_configmapguard: acustom configuration is now responsible for the clusters, Lua filter and routes the generated one
would have added.
keda.minReplicaCountgoes to 0, so no Slurm allocation is held while idle.envoy-config.yamlis rewritten as the configuration the chart generates, plus the three thingsa Triton behind a Slurm-side wstunnel needs that the chart cannot express:
and, from the generated side: the Lua filter, the
triton_admission(127.0.0.1:8080) andenvoy_admin(127.0.0.1:9901) clusters, theRepositoryIndexroute,dns_refresh_rate: 1sandconnect_timeout: 2s. The Lua filter sits ahead of the buffer so a wake starts on the headersrather than after a body has been buffered.
The one number worth arguing about
readyTimeoutSeconds: 900, where the other releases use 300. Waking here queues a Slurm job onHammer and waits for it to start, rather than scheduling a pod. The route's
idle_timeoutfollowsat 1020s — the
readyTimeoutSeconds + 120margin the chart applies. Both are guesses at Hammer'squeue for one GPU; if RepositoryIndex starts timing out, those are the two to raise, and they move
together by hand because the config file cannot read the values.
A client calling RepositoryIndex on a cold release will now block for up to 15 minutes rather than
fail fast. That is the deliberate trade.
Checks
envoy --mode validateaccepts the config against the chart's rendered Lua filter — 3 clusters,1 listener, Lua compiled; the only warning is the deprecated
dns_refresh_ratethe chart itselfemits.
validate-manifests.sh✓ 32 HelmReleases, 188 resources ·pre-commit --all-files✓ ·pytest tests/manifests✓ 166 passed.Note the validator skips this release (its Envoy config is read via
lookup, whichhelm templatecannot resolve), so the values were rendered separately with
external_config.load_from_configmap=false, and the sidecar wiring was confirmed by reading thechart templates: the Lua ConfigMap and the admission sidecar are gated on
scaleFromZeroalone,with no
external_configcondition.Whether a wake actually completes inside 900s is for the first cold start on Hammer to answer.
🤖 Generated with Claude Code