Skip to content

Performance audit: systematic review of bottlenecks across HTTP, CPU, memory, and concurrency #824

@dangrondahl

Description

@dangrondahl

Context

Triggered by #822 / commit 251f3bc, where json.MarshalIndent was inflating multipart payloads by ~2x. A full codebase audit was performed to find similar and other performance issues.

Four parallel investigations covered HTTP/network, CPU/algorithms, memory/allocations, and concurrency/I/O. 30+ raw findings were deduplicated into 18 unique issues across 3 priority tiers.

Tier 1 — High Impact, Fix Soon

# Issue Location Category Ticket
1 context.TODO() across all AWS API calls — no timeout, no cancellation. ECS/Lambda/S3 calls can hang indefinitely. ~15 call sites. internal/aws/aws.go Concurrency
2 Bare &http.Client{} without timeouts in 4 locations. A slow server hangs the CLI forever. sonar.go:162, azure_apps.go:167,201, update_check.go:84 HTTP
3 json.MarshalIndent still used for non-multipart request bodies (line 122). Same class of bug as #822 — all regular JSON POST/PUT payloads inflated with whitespace. internal/requests/requests.go:122 HTTP/Payload #825
4 Sequential S3 file downloads — files downloaded one-by-one. Wall-clock time scales linearly with object count. internal/aws/aws.go:373–422 Concurrency
5 regexp.Compile() called per-item in K8s namespace filtering, git commit matching, and digest validation — 3 hot paths. resourceFilter.go:29,45, gitView.go:288, digest.go:359 CPU #826
6 No connection pooling configured on Kosli HTTP client — no MaxIdleConns, IdleConnTimeout, or keep-alive tuning. internal/requests/requests.go:60–71 HTTP

Tier 2 — Medium Impact

# Issue Location Category Ticket
7 Unbounded io.ReadAll on HTTP responses — no size limit. Large API responses or Azure logs could OOM. requests.go:259, azure_apps.go:179,519,543 Memory
8 Directory fingerprinting: sequential hashing + temp file created per filename to hash a string. internal/digest/digest.go:119–225 CPU/I/O
9 K8s processPods(): unbounded goroutines (1 per pod, no semaphore) + corev1.Pod passed by value (full struct copy). internal/kube/kube.go:178–229 Concurrency/Memory
10 GitHub PR evidence: sequential queries with hard-coded 10/20/30s retry sleeps. internal/github/github.go:281–282 Concurrency
11 No jitter in retry backoff — thundering herd risk with multiple CLI instances. internal/requests/requests.go:327–342 HTTP
12 PayloadOutput double-buffers entire request body for debug logging. internal/requests/requests.go:316–321 Memory

Tier 3 — Low Impact / Localized

# Issue Location Category Ticket
13 Sequential SonarQube API calls (4 serial round-trips) internal/sonar/sonar.go:219–243 Concurrency
14 Bitbucket PR pagination is sequential internal/bitbucket/bitbucket.go:200–266 Concurrency
15 Azure zip fingerprinting doesn't reuse bearer tokens internal/azure/azure_apps.go:237–241 HTTP
16 String += in loops cli_utils.go:314,320, multiHost.go:60,76 CPU
17 Slice/map pre-allocation missing internal/github/github.go:114,408 Memory
18 Unnecessary string↔[]byte conversions in HTTPResponse internal/requests/requests.go:270,295 Memory

Bonus: Correctness Bug

os.WriteFile("zipFileName", ...) at azure_apps.go:526 uses a string literal instead of the variable zipFileName. The surrounding code is unfinished (has TODOs, returns nil), but will be a bug when completed.

Recommended Phases

  1. Quick wins — items 3 (MarshalIndent) and 5 (regex compilation). Same patterns as the triggering fix.
  2. Resilience — items 1, 2, 6. Prevent hangs in CI/CD.
  3. Throughput — items 4, 8, 9, 10. Biggest latency improvements.
  4. Hardening — items 7, 11, 12. Defensive limits.

Metadata

Metadata

Assignees

No one assigned

    Labels

    performanceIssues related to performance bottlenecks or improvements

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions