Skip to content

Instantly share code, notes, and snippets.

@mannion007
Last active April 13, 2020 21:51
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 mannion007/c4d334ec8565e98851d9759c81eea20c to your computer and use it in GitHub Desktop.
Save mannion007/c4d334ec8565e98851d9759c81eea20c to your computer and use it in GitHub Desktop.
Ninja Level 3 Hands on Exercise #4
package main
import (
"context"
"fmt"
"time"
profiler "github.com/mannion007/whatever/profiler"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*1005)
defer cancel()
endpoints := []string{
"http://www.google.co.uk",
"http://www.google.co.in",
"http://www.ebay.co.uk",
"http://www.ebay.co.jp",
"http://www.twitter.com",
"https://www.facebook.com",
"http://www.youtube.com",
"http://www.deliveroo.co.uk",
"http://www.github.com",
"http://www.iflscience.com",
}
results, errors := profiler.Profile(ctx, endpoints)
for i := 0; i <= len(endpoints); i++ {
select {
case result := <-results:
fmt.Printf("Success [%s] responded in [%v]\n", result.URL, result.ResponseTime)
case err := <-errors:
fmt.Printf("Error [%s]\n", err)
}
}
}
package poller
import (
"context"
"fmt"
"net/http"
"time"
)
// Endpoint is a struct which represents the measured performance of an endpoint
type Endpoint struct {
URL string
ResponseTime time.Duration
}
// Profile sends a GET request to each of the endpoints in the supplied list and times how long it takes to respond
func Profile(ctx context.Context, endpoints []string) (<-chan Endpoint, <-chan error) {
successChan := make(chan Endpoint)
errorChan := make(chan error)
for _, ep := range endpoints {
go func(ctx context.Context, url string, output chan<- Endpoint, errorChan chan<- error) {
start := time.Now()
// Don't bother to even start a request if <1 second remaining. Doesn't make much sense given how quickly Go routines spawn, but demonstrates utilisation of context deadline
deadline, ok := ctx.Deadline()
if ok && deadline.Before(time.Now().Add(time.Second)) {
errorChan <- fmt.Errorf("skipping profiling [%s] as there is less than 1 second to go", url)
return
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
errorChan <- fmt.Errorf("error building request for [%s]", url)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
errorChan <- fmt.Errorf("failed profiling endpoint [%s] [%s]", url, err)
return
}
if resp.StatusCode != http.StatusOK {
errorChan <- fmt.Errorf("Unexpected response code from [%s] [%d]", url, resp.StatusCode)
}
output <- Endpoint{
URL: url,
ResponseTime: time.Since(start),
}
}(ctx, ep, successChan, errorChan)
}
return successChan, errorChan
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment