Skip to content

Instantly share code, notes, and snippets.

@konradko
Last active August 27, 2016 14:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save konradko/1a8a6b09b2272163c4c971a686760cb7 to your computer and use it in GitHub Desktop.
Save konradko/1a8a6b09b2272163c4c971a686760cb7 to your computer and use it in GitHub Desktop.
Sending HTTP requests concurrently with Go
package main
import (
"flag"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"
"time"
)
var (
httpClient = http.Client{Timeout: time.Duration(10 * time.Second)}
url = flag.String("url", "https://example.com", "Destination URL")
)
type httpResponse struct {
payload string
statusCode int
err error
}
func asyncPost(payloads []string) (err error) {
// Send ~150 requests per second
throttle := time.Tick(time.Second / 150)
ch := make(chan *httpResponse)
sentCounter := 0
for _, payload := range payloads {
go func(payload string) {
log.Infof("Sending %s \n", payload)
<-throttle
ch <- post(payload)
}(payload)
}
for {
select {
case r := <-ch:
if r.err != nil || r.statusCode != 200 {
if r.err != nil {
log.Errorf("Error sending %s: %s", r.payload, r.err)
} else if r.statusCode != 200 {
log.Infoln("Non-200 response status code for %s: %s", r.payload, r.statusCode)
}
} else {
log.Infof("%s sent\n", r.payload)
}
sentCounter++
if sentCounter == len(payloads) {
return
}
case <-time.After(50 * time.Millisecond):
fmt.Printf(".")
}
}
}
func post(payload string) *httpResponse {
reader := strings.NewReader(payload)
req, _ := http.NewRequest("POST", *url, reader)
resp, err := httpClient.Do(req)
var statusCode int
if resp != nil {
statusCode = resp.StatusCode
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
}
return &httpResponse{statusCode: statusCode, payload: payload, err: err}
}
func main() {
asyncPost([]string{"payload1", "payload2", "payload3"})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment