Retry repeats a failed network operation when the failure may be temporary. For HTTP connections, detect timeout conditions, retry while attempts remain, and otherwise return the error for logging or alerting. section 11.1.2
A practical retry implementation combines failure detection with bounded recovery:
- Check errors from net, http, and url operations for recognized timeout cases, including wrapped errors and closed network connections. section 11.1.2
- Retry only while a retry count remains, decrementing the count on each recursive download attempt. section 11.1.2
- Resume a partially written download by setting an HTTP Range header from the existing file size. section 11.1.2
- Use an HTTP client timeout and return non-timeout errors without treating them as retryable failures. section 11.1.2
Listing 11.5 Download with retries
func download(location string, file *os.File, retries int64) error {
req, err := http.NewRequest("GET", location, nil) #1
if err != nil {
return err
}
fi, err := file.Stat() #2
if err != nil { #4
return err #4
} #4
current := fi.Size() #3
if current > 0 { #4
start := strconv.FormatInt(current, 10) #4
req.Header.Set("Range", "bytes="+start+"-") #4
} #4
cc := &http.Client{Timeout: 5 * time.Minute} #5
res, err := cc.Do(req) #6
if err != nil && hasTimedOut(err) { #7
if retries > 0 {
return download(location, file,
retries-1)
}
return err
} else if err != nil {
return err
}
if res.StatusCode < 200 || res.StatusCode > 300 { #8
errFmt := "Unsuccess HTTP request. Status
: %s"
return fmt.Errorf(errFmt, res.Status)
}
if res.Header.Get("Accept-Ranges") != "bytes" { #9
retries = 0 #9
} #9
_, err = io.Copy(file, res.Body) #10
if err != nil && hasTimedOut(err) { #11
if retries > 0 {
return download(location, file,
retries-1)
}
return err
} else if err != nil {
return err
}
return nil
}
Shows a Go download function that creates a request, resumes from the current file size, applies a client timeout, and retries detected timeouts. section 11.1.2




















