// handleSerialSubrequests executes two slow running sub-requests // serially with a timeout. // // both sub-requests succeed: // curl localhost:8080/subrequests/serial?timeout=1100ms // one fails, one succeeds: // curl localhost:8080/subrequests/serial?timeout=700ms // both fail: // curl localhost:8080/subrequests/serial?timeout=400ms func handleSerialSubrequests(ctx context.Context, w http.ResponseWriter, r *http.Request) { // Require the caller to specify an overall timeout, like 700ms. timeoutStr := r.URL.Query().Get("timeout") timeout, err := time.ParseDuration(timeoutStr) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte("Invalid timeout query parameter. Expected something like timeout=700ms")) return } ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() start := time.Now() get := func(i int) (string, error) { var result string err := httpGet(ctx, localURL("slow/get?delay=500ms"), func(r *http.Response, err error) error { if err != nil { clog.Debugf(ctx, "handleTimeout: get %v failed. %v", i, err) return err } b, err := ioutil.ReadAll(r.Body) if err != nil { clog.Debugf(ctx, "handleTimeout: get %v ReadAll failed. %v", i, err) return err } clog.Debugf(ctx, "handleTimeout: get %v returned with: %v", i, string(b)) result = string(b) return nil }) return result, err } subRequestCount := 2 subResults := make([]string, 0) for i := 0; i < subRequestCount; i++ { r, err := get(i) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Sub-request %v failed. %v", i, err.Error()))) return } subResults = append(subResults, r) } duration := time.Since(start) result := fmt.Sprintf("Duration: %v\nResults:%v", duration, strings.Join(subResults, "\n")) w.Write([]byte(result)) }
// handleConhandleConcurrentSubrequests executes two slow running sub-requests // concurrently with a timeout. If the timeout expires, the results it has // obtained so far are returned. // // both sub-requests succeed: // curl localhost:8080/subrequests/concurrent?timeout=800ms // one fails, one succeeds: // curl localhost:8080/subrequests/concurrent?timeout=700ms // both fail: // curl localhost:8080/subrequests/concurrent?timeout=400ms func handleConcurrentSubrequests(ctx context.Context, w http.ResponseWriter, r *http.Request) { // Require the caller to specify an overall timeout, like 700ms. clog.Debug(ctx, "In handleConcurrentSubrequests test log message") timeoutStr := r.URL.Query().Get("timeout") timeout, err := time.ParseDuration(timeoutStr) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte("Invalid timeout query parameter. Expected something like timeout=700ms")) return } ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() type subRequestResult struct { err error requestNumber int result string } out := make(chan subRequestResult) start := time.Now() subRequestDelays := []time.Duration{500 * time.Millisecond, 750 * time.Millisecond} for i, delay := range subRequestDelays { i := i // shadow mutable counter for closure delay := delay // shadow for closure go func() { var result string url := localURL(fmt.Sprintf("slow/get?delay=%v", delay)) err := httpGet(ctx, url, func(r *http.Response, err error) error { if err != nil { clog.Debugf(ctx, "handleTimeout: get %v failed. %v", i, err) return err } b, err := ioutil.ReadAll(r.Body) if err != nil { clog.Debugf(ctx, "handleTimeout: get %v ReadAll failed. %v", i, err) return err } clog.Debugf(ctx, "handleTimeout: get %v returned with: %v", i, string(b)) result = string(b) return nil }) out <- subRequestResult{err, i, result} }() if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Sub request %v failed. %v", i, err.Error()))) return } } r1 := <-out r2 := <-out duration := time.Since(start) toString := func(s subRequestResult) string { if s.err != nil { return fmt.Sprintf("Request Number: %v, Error: %v", s.requestNumber, s.err.Error()) } else { return fmt.Sprintf("Request Number: %v, Result: %v", s.requestNumber, s.result) } } result := fmt.Sprintf("Duration: %v\n%v\n%v", duration, toString(r1), toString(r2)) w.Write([]byte(result)) }
func okHandler(c context.Context, w http.ResponseWriter, r *http.Request) { clog.Debugf(c, "Responding with 'ok' for %v", r.URL) w.Write([]byte("ok")) }