Go: cancel the rest of a batch after the first 402 on Sume

A Go fan-out that stops launching Wan 3.0 submits the moment one returns 402 insufficient_credits, using context.WithCancel and a 2-slot semaphore.

4 min readSume
All posts

When the balance runs out in the middle of a batch, every remaining submit will fail the same way. Sume's docs say a generation submit returns 402 insufficient_credits before provider work starts, so the failed calls cost nothing, but sending 40 more of them is noise and rate-limit budget you do not need to spend.

The Go program below launches shots through a 2-slot semaphore and keeps a context.WithCancel. The goroutine that sees a 402 calls stop(), and the launch loop checks the context before starting the next shot. Shots that were never sent stay at 0 in the result slice. It was run with a local stand-in that returns 202 four times and then 402; it was not pointed at the live API.

The code (30 lines)

The context also goes into NewRequestWithContext, so a request that has not been written yet is abandoned when the batch is stopped. Requests already on the wire finish normally.

package main
import ("context"; "fmt"; "net/http"; "os"; "strings"; "sync")
func submit(ctx context.Context, i int) int {
	body := fmt.Sprintf(`{"model":"wan-3.0","prompt":"shot %d","duration":5,"resolution":"480p"}`, i)
	req, _ := http.NewRequestWithContext(ctx, "POST", os.Getenv("SUME_BASE")+"/v1/videos", strings.NewReader(body))
	req.Header.Set("x-api-key", os.Getenv("SUME_API_KEY"))
	req.Header.Set("content-type", "application/json")
	req.Header.Set("Idempotency-Key", fmt.Sprintf("trailer-v4-shot-%02d", i))
	res, err := http.DefaultClient.Do(req)
	if err != nil { return 0 }
	res.Body.Close()
	return res.StatusCode
}
func main() {
	ctx, stop := context.WithCancel(context.Background())
	codes, sem := make([]int, 12), make(chan struct{}, 2)
	var wg sync.WaitGroup
	for i := range codes {
		sem <- struct{}{}
		if ctx.Err() != nil { <-sem; break } // a 402 already told us the balance is gone
		wg.Add(1)
		go func() {
			defer wg.Done()
			defer func() { <-sem }()
			if codes[i] = submit(ctx, i); codes[i] == 402 { stop() }
		}()
	}
	wg.Wait()
	fmt.Println(codes) // 0 = never sent
}

What the run printed

With a stub that accepted four submits and then answered 402, the result slice looked like this.

[202 202 202 202 402 0 0 0 0 0 0 0]

After the top-up

Zeros mean never sent, so those are the shots to resend once credits are added. The four accepted shots keep their jobs; resubmitting them with the same Idempotency-Key returns the originals instead of billing twice. Check GET /v1/balance before restarting rather than finding the next 402 the hard way.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume