feat(download): implement parallel download workers with retry and backoff #137

Merged
fuzzy merged 2 commits from feat/parallel-download-workers into main 2026-07-13 18:09:23 +00:00
Owner

What

Implement the core parallel download engine: worker pool, chunked download for HTTP and FTP, file pre-allocation, WriteAt positioning, and retry with exponential backoff.

Why

This is the heart of pget — orchestrates N concurrent workers to download chunks and assemble them into the output file.

Testing

  • go vet ./... passes
  • go build ./... passes
  • golangci-lint run ./... passes
  • Pre-commit hooks pass

Breaking Changes

Removed internal/downloader/downloader.go stub — replaced by download.go.

Notes

  • Download() — main entry point: probes URL, splits chunks, spawns workers
  • HTTP: uses Range header + http.Client.Do() with context cancellation
  • FTP: uses RetrFrom(offset) for chunked downloads
  • preallocFile — creates sparse file via Truncate(size)
  • writeAtSeeker — wraps *os.File + WriteAt for per-chunk offset positioning
  • Retry: up to 3 attempts with exponential backoff (1s, 2s, 4s)
  • Single-threaded fallback when server lacks range/REST support or file size is unknown

Closes #0040
Closes #0041
Closes #0042
Closes #0043
Closes #0044
Closes #0045
Closes #0046

## What Implement the core parallel download engine: worker pool, chunked download for HTTP and FTP, file pre-allocation, `WriteAt` positioning, and retry with exponential backoff. ## Why This is the heart of pget — orchestrates N concurrent workers to download chunks and assemble them into the output file. ## Testing - [x] `go vet ./...` passes - [x] `go build ./...` passes - [x] `golangci-lint run ./...` passes - [x] Pre-commit hooks pass ## Breaking Changes Removed `internal/downloader/downloader.go` stub — replaced by `download.go`. ## Notes - `Download()` — main entry point: probes URL, splits chunks, spawns workers - HTTP: uses `Range` header + `http.Client.Do()` with context cancellation - FTP: uses `RetrFrom(offset)` for chunked downloads - `preallocFile` — creates sparse file via `Truncate(size)` - `writeAtSeeker` — wraps `*os.File` + `WriteAt` for per-chunk offset positioning - Retry: up to 3 attempts with exponential backoff (1s, 2s, 4s) - Single-threaded fallback when server lacks range/REST support or file size is unknown Closes #0040 Closes #0041 Closes #0042 Closes #0043 Closes #0044 Closes #0045 Closes #0046
Closes #0040 Closes #0041 Closes #0042 Closes #0043 Closes #0044 Closes #0045 Closes #0046
docs(roadmap): mark parallel download workers complete
All checks were successful
Test and Release / test (pull_request) Successful in 1m57s
Test and Release / lint (pull_request) Successful in 2m59s
63c65c63c1
fuzzy scheduled this pull request to auto merge when all checks succeed 2026-07-13 18:06:28 +00:00
the.auditor left a comment

Review: APPROVED

Verification

  • go vet ./... passes
  • go build ./... passes
  • golangci-lint v2 run ./... 0 issues

Changes

  • internal/downloader/download.go (new, 207 lines) — Download engine: worker pool, chunked HTTP/FTP download, WriteAt positioning, retry with exponential backoff, single-threaded fallback
  • internal/downloader/downloader.go — deleted (replaced by download.go)
  • ROADMAP.md — Marks Phase 2 parallel download items as [x]

Suggestions (non-blocking)

  • #138 — Single-threaded fallback produces empty file when Content-Length unknown
  • #139 — Missing tests for download engine
  • #140 — Workers continue running after first failure; use context.WithCancel

Closes #0040, #0041, #0042, #0043, #0044, #0045, #0046 on merge.

## Review: APPROVED ### Verification - `go vet ./...` — ✅ passes - `go build ./...` — ✅ passes - `golangci-lint v2 run ./...` — ✅ 0 issues ### Changes - `internal/downloader/download.go` (new, 207 lines) — Download engine: worker pool, chunked HTTP/FTP download, WriteAt positioning, retry with exponential backoff, single-threaded fallback - `internal/downloader/downloader.go` — deleted (replaced by download.go) - `ROADMAP.md` — Marks Phase 2 parallel download items as [x] ### Suggestions (non-blocking) - #138 — Single-threaded fallback produces empty file when Content-Length unknown - #139 — Missing tests for download engine - #140 — Workers continue running after first failure; use context.WithCancel Closes #0040, #0041, #0042, #0043, #0044, #0045, #0046 on merge.
fuzzy merged commit 63c65c63c1 into main 2026-07-13 18:09:23 +00:00
fuzzy deleted branch feat/parallel-download-workers 2026-07-13 18:09:23 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
thwap/pget!137
No description provided.