blob: 8aed2d88a19e3aeb29012b468b9f3abce422cc1c [file] [log] [blame]
Alexander Rakoczy75882ed2021-07-20 17:34:23 -04001// Copyright 2021 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build go1.16
6// +build go1.16
7
8package main
9
10import (
11 "context"
12 "fmt"
13 "io"
14 "net/http"
15 "time"
16
17 "golang.org/x/build/internal"
18)
19
20// buildletHealthTimeout is the maximum time to wait for a
21// checkBuildletHealth request to complete.
22const buildletHealthTimeout = 10 * time.Second
23
24// checkBuildletHealth performs a GET request against URL, and returns
25// an error if an http.StatusOK isn't returned before
26// buildletHealthTimeout has elapsed.
27func checkBuildletHealth(ctx context.Context, url string) error {
28 ctx, cancel := context.WithTimeout(ctx, buildletHealthTimeout)
29 defer cancel()
30 req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
31 if err != nil {
32 return err
33 }
34 resp, err := http.DefaultClient.Do(req)
35 if err != nil {
36 return err
37 }
38 defer resp.Body.Close()
39 if _, err := io.Copy(io.Discard, resp.Body); err != nil {
40 return err
41 }
42 if resp.StatusCode != http.StatusOK {
43 return fmt.Errorf("resp.StatusCode = %d, wanted %d", resp.StatusCode, http.StatusOK)
44 }
45 return nil
46}
47
48// heartbeatContext calls f every period. If f consistently returns an
49// error for longer than the provided timeout duration, the context
50// returned by heartbeatContext will be cancelled, and
51// heartbeatContext will stop sending requests.
52//
53// A single call to f that does not return an error will reset the
54// timeout window, unless heartbeatContext has already timed out.
55func heartbeatContext(ctx context.Context, period time.Duration, timeout time.Duration, f func(context.Context) error) (context.Context, func()) {
56 ctx, cancel := context.WithCancel(ctx)
57
58 lastSuccess := time.Now()
59 go internal.PeriodicallyDo(ctx, period, func(ctx context.Context, t time.Time) {
60 err := f(ctx)
61 if err != nil && t.Sub(lastSuccess) > timeout {
62 cancel()
63 }
64 if err == nil {
65 lastSuccess = t
66 }
67 })
68
69 return ctx, cancel
70}