Skip to content

Commit 44e74d5

Browse files
committed
buildlet: don't leak file descriptors to buildlets
Also, add count of fds and goroutines to the coordinator's status page. Change-Id: I857e609623cfa280716d5d079180d0e4021d0bac Reviewed-on: https://go-review.googlesource.com/27550 Reviewed-by: Quentin Smith <[email protected]>
1 parent 1615165 commit 44e74d5

File tree

2 files changed

+53
-15
lines changed

2 files changed

+53
-15
lines changed

buildlet/buildletclient.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,17 @@ import (
3131
//
3232
// This constructor returns immediately without testing the host or auth.
3333
func NewClient(ipPort string, kp KeyPair) *Client {
34+
tr := &http.Transport{
35+
Dial: defaultDialer(),
36+
DialTLS: kp.tlsDialer(),
37+
IdleConnTimeout: time.Minute,
38+
}
3439
c := &Client{
35-
ipPort: ipPort,
36-
tls: kp,
37-
password: kp.Password(),
38-
httpClient: &http.Client{
39-
Transport: &http.Transport{
40-
Dial: defaultDialer(),
41-
DialTLS: kp.tlsDialer(),
42-
},
43-
},
40+
ipPort: ipPort,
41+
tls: kp,
42+
password: kp.Password(),
43+
httpClient: &http.Client{Transport: tr},
44+
closeFuncs: []func(){tr.CloseIdleConnections},
4445
}
4546
c.setCommon()
4647
return c
@@ -83,6 +84,9 @@ func (c *Client) Close() error {
8384
if err == nil {
8485
err = ErrClosed
8586
}
87+
for _, fn := range c.closeFuncs {
88+
fn()
89+
}
8690
c.setPeerDead(err) // which will also cause c.heartbeatFailure to run
8791
})
8892
return nil
@@ -133,6 +137,8 @@ type Client struct {
133137
password string // basic auth password or empty for none
134138
remoteBuildlet string // non-empty if for remote buildlets
135139

140+
closeFuncs []func() // optional extra code to run on close
141+
136142
ctx context.Context
137143
ctxCancel context.CancelFunc
138144
heartbeatFailure func() // optional

cmd/coordinator/status.go

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ import (
88
"bytes"
99
"fmt"
1010
"html/template"
11+
"io"
1112
"net/http"
13+
"os"
1214
"os/exec"
15+
"runtime"
1316
"sort"
1417
"strings"
1518
"time"
@@ -27,11 +30,13 @@ func handleStatus(w http.ResponseWriter, r *http.Request) {
2730

2831
statusMu.Lock()
2932
data := statusData{
30-
Total: len(status),
31-
Uptime: round(time.Now().Sub(processStartTime)),
32-
Recent: append([]*buildStatus{}, statusDone...),
33-
DiskFree: df,
34-
Version: Version,
33+
Total: len(status),
34+
Uptime: round(time.Now().Sub(processStartTime)),
35+
Recent: append([]*buildStatus{}, statusDone...),
36+
DiskFree: df,
37+
Version: Version,
38+
NumFD: fdCount(),
39+
NumGoroutine: runtime.NumGoroutine(),
3540
}
3641
for _, st := range status {
3742
data.Active = append(data.Active, st)
@@ -85,14 +90,35 @@ func handleStatus(w http.ResponseWriter, r *http.Request) {
8590
buf.WriteTo(w)
8691
}
8792

93+
func fdCount() int {
94+
f, err := os.Open("/proc/self/fd")
95+
if err != nil {
96+
return -1
97+
}
98+
defer f.Close()
99+
n := 0
100+
for {
101+
names, err := f.Readdirnames(1000)
102+
n += len(names)
103+
if err == io.EOF {
104+
return n
105+
}
106+
if err != nil {
107+
return -1
108+
}
109+
}
110+
}
111+
88112
func diskFree() string {
89113
out, _ := exec.Command("df", "-h").Output()
90114
return string(out)
91115
}
92116

93117
// statusData is the data that fills out statusTmpl.
94118
type statusData struct {
95-
Total int
119+
Total int // number of total builds active
120+
NumFD int
121+
NumGoroutine int
96122
Uptime time.Duration
97123
Active []*buildStatus
98124
Recent []*buildStatus
@@ -157,6 +183,12 @@ var statusTmpl = template.Must(template.New("status").Parse(`
157183
<h2 id=disk><a href='#disk'>🔗</a> Disk Space</h2>
158184
<pre>{{.DiskFree}}</pre>
159185
186+
<h2 id=disk><a href='#fd'>🔗</a> File Descriptors</h2>
187+
<p>{{.NumFD}}</p>
188+
189+
<h2 id=disk><a href='#goroutines'>🔗</a> Goroutines</h2>
190+
<p>{{.NumGoroutine}} <a href='/debug/goroutines'>goroutines</a></p>
191+
160192
</body>
161193
</html>
162194
`))

0 commit comments

Comments
 (0)