Last active
October 11, 2016 21:20
-
-
Save vcabbage/a41b96c4b9ef0af128ac1227c44b3536 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"log" | |
"net/http" | |
"time" | |
"golang.org/x/sync/singleflight" | |
) | |
func main() { | |
var requestGroup singleflight.Group | |
http.HandleFunc("/github", func(w http.ResponseWriter, r *http.Request) { | |
// With DoChan we get a channel of singleflight.Result | |
ch := requestGroup.DoChan("github", func() (interface{}, error) { | |
return githubStatus() | |
}) | |
// Create our timeout | |
timeout := time.After(500 * time.Millisecond) | |
var result singleflight.Result | |
select { | |
case <-timeout: // Timeout elapsed, send a timeout message (504) | |
log.Println("/github handler timed out") | |
http.Error(w, "github request timed out", http.StatusGatewayTimeout) | |
return | |
case result = <-ch: // Received result from channel | |
} | |
// singleflight.Result is the same three values as returned from Do(), but wrapped | |
// in a struct. We can use the same logic as before, buy referencing the struct fields. | |
if result.Err != nil { | |
http.Error(w, result.Err.Error(), http.StatusInternalServerError) | |
return | |
} | |
status := result.Val.(string) | |
log.Printf("/github handler requst: status %q, shared result %t", status, result.Shared) | |
fmt.Fprintf(w, "GitHub Status: %q", status) | |
}) | |
http.ListenAndServe("127.0.0.1:8080", nil) | |
} | |
// githubStatus retrieves GitHub's API status | |
func githubStatus() (string, error) { | |
log.Println("Making request to GitHub API") | |
defer log.Println("Request to GitHub API Complete") | |
time.Sleep(1 * time.Second) | |
resp, err := http.Get("https://status.github.com/api/status.json") | |
if err != nil { | |
return "", err | |
} | |
defer resp.Body.Close() | |
if resp.StatusCode != 200 { | |
return "", fmt.Errorf("github response: %s", resp.Status) | |
} | |
r := struct{ Status string }{} | |
err = json.NewDecoder(resp.Body).Decode(&r) | |
return r.Status, err | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment