Я бы повесил timeout (уменьшил бы его до приемлемого).
Если ответ не пришёл в течение N секунд - возвращать ошибку.
Timeout создается при помощи добавления кастомного http.Transport в конструктор http.Client (15-20 строки).
Код программы c timeout'ом.package main
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"time"
)
func getPage(url string, timeout time.Duration) (HTML string, e error) {
client := &http.Client{
Transport: &http.Transport{
Dial: func(network, addr string) (net.Conn, error) {
return net.DialTimeout(network, addr, timeout)
},
ResponseHeaderTimeout: timeout,
},
}
req, e := http.NewRequest("GET", url, nil)
if e != nil {
return "", errors.New(fmt.Sprintf(`http.NewRequest failed: %s`, e.Error()))
}
resp, e := client.Do(req)
if e != nil {
return "", errors.New(fmt.Sprintf("client.Do failed: %s)", e.Error()))
}
defer resp.Body.Close()
bodyAsBytes, e := ioutil.ReadAll(resp.Body)
if e != nil {
return "", errors.New(fmt.Sprintf("ioutil.ReadAll failed: %s)", e.Error()))
}
bodyAsBuffer := bytes.NewBuffer(bodyAsBytes)
return bodyAsBuffer.String(), nil
}
func main() {
HTML, e := getPage("http://google.com/", time.Duration(1*time.Second))
if e != nil {
fmt.Printf("[ERROR] %s\n", e.Error())
} else {
fmt.Printf("[INFO] %s\n", HTML)
}
}
Если timeout выставить так (1 наносекунда), то программа выведет сообщение об ошибке:
>>> HTML, e := getPage("http://google.com/", time.Duration(1*time.Nanosecond))
[ERROR] client.Do failed: Get http://google.com/: i/o timeout)
Если timeout выставить так (5 секунд), то программа выведет HTML странички:
HTML, e := getPage("http://google.com/", time.Duration(5*time.Second))
[INFO] <!doctype html><html itemscope="" itemtype="http://schema.org/WebPage"><head><meta content="........
Я сделал бы pool задач на скачивание. Если некоторые не завершились успехом - перезапускал бы их через некоторое время. На мой взгляд это типичная задача pool - worker:
1) Можно решать через
resque +
goworker например. Это дает наглядность. Упавшие задачи можно сразу перезапустить, увидеть что пошло не так. Статистика копится;
2) Можно решать, создав горутину как pool и N горутин как worker'ы. И самому создать логику обработки упавших задач.