Skip to content

perf: multipart body rebuilt from scratch on every poll retry, re-serializing full zip each time #33

@claude

Description

@claude

Problem

In both GetGraph (internal/api/client.go:285-296) and GetCircularDependencies (internal/api/client.go:416-426), the multipart body is constructed inside the polling loop. On every retry attempt, the entire repo zip is re-serialized into a new multipart body:

for attempt := 0; attempt < maxPollAttempts; attempt++ {
var body bytes.Buffer
mw := multipart.NewWriter(&body)
fw.Write(repoZip) // copies the full zip on every attempt
...
}

With maxPollAttempts = 90 and a repo zip up to 10 MB, this can mean copying up to 900 MB of data across retries, with a fresh allocation on each pass. The multipart body content is identical every time since both the idempotency key and zip data are constant across the loop.

Fix

Build the multipart body once before the loop, capture it as a []byte, and use bytes.NewReader on each attempt so the reader can be reset:

// Build once
var bodyBuf bytes.Buffer
mw := multipart.NewWriter(&bodyBuf)
...
mw.Close()
bodyBytes := bodyBuf.Bytes()
contentType := mw.FormDataContentType()

for attempt := 0; attempt < maxPollAttempts; attempt++ {
req, _ := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(bodyBytes))
...
}

This applies to both GetGraph and GetCircularDependencies.

Affected files

  • internal/api/client.go:274-395 (GetGraph polling loop)
  • internal/api/client.go:400-528 (GetCircularDependencies polling loop)

@claude please implement this

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions