Skip to content

Commit eeb1a98

Browse files
authored
Merge pull request sourcegraph#101 from sourcegraph/sg/context-timeout
langserver: add 15s timeout to workspace/xreferences
2 parents 24b8161 + 87fbe68 commit eeb1a98

File tree

1 file changed

+54
-7
lines changed

1 file changed

+54
-7
lines changed

langserver/workspace_refs.go

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"sort"
1414
"strings"
1515
"sync"
16+
"time"
1617

1718
"golang.org/x/tools/go/loader"
1819

@@ -23,7 +24,17 @@ import (
2324
"github.com/sourcegraph/jsonrpc2"
2425
)
2526

27+
// workspaceReferencesTimeout is the timeout used for workspace/xreferences
28+
// calls.
29+
const workspaceReferencesTimeout = 15 * time.Second
30+
2631
func (h *LangHandler) handleWorkspaceReferences(ctx context.Context, conn JSONRPC2Conn, req *jsonrpc2.Request, params lspext.WorkspaceReferencesParams) ([]referenceInformation, error) {
32+
// TODO: Add support for the cancelRequest LSP method instead of using
33+
// hard-coded timeouts like this here.
34+
//
35+
// See: https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#cancelRequest
36+
ctx, cancel := context.WithTimeout(ctx, workspaceReferencesTimeout)
37+
defer cancel()
2738
rootPath := h.FilePath(h.init.RootPath)
2839
bctx := h.BuildContext(ctx)
2940

@@ -101,13 +112,37 @@ func (h *LangHandler) handleWorkspaceReferences(ctx context.Context, conn JSONRP
101112
}()
102113
}
103114

104-
_, err := h.workspaceRefsTypecheck(ctx, bctx, conn, fset, pkgs, afterTypeCheck)
105-
if err != nil {
106-
return nil, err
107-
}
115+
// workspaceRefsTypecheck is ran inside it's own goroutine because it can
116+
// block for longer than our context deadline.
117+
var err error
118+
done := make(chan struct{})
119+
go func() {
120+
// Prevent any uncaught panics from taking the entire server down.
121+
defer func() {
122+
if r := recover(); r != nil {
123+
// Same as net/http
124+
const size = 64 << 10
125+
buf := make([]byte, size)
126+
buf = buf[:runtime.Stack(buf, false)]
127+
log.Printf("ignoring panic serving %v for pkgs %v: %v\n%s", req.Method, pkgs, r, buf)
128+
return
129+
}
130+
}()
108131

109-
// Wait for all worker goroutines to complete.
110-
wg.Wait()
132+
_, err = h.workspaceRefsTypecheck(ctx, bctx, conn, fset, pkgs, afterTypeCheck)
133+
134+
// Wait for all worker goroutines to complete.
135+
wg.Wait()
136+
close(done)
137+
}()
138+
select {
139+
case <-done:
140+
if err != nil {
141+
return nil, err
142+
}
143+
case <-ctx.Done():
144+
return nil, ctx.Err()
145+
}
111146

112147
sort.Sort(&results) // sort to provide consistent results
113148
return results.results, nil
@@ -149,7 +184,12 @@ func (h *LangHandler) workspaceRefsTypecheck(ctx context.Context, bctx *build.Co
149184
}
150185
return bpkg, nil
151186
},
152-
AfterTypeCheck: afterTypeCheck,
187+
AfterTypeCheck: func(pkg *loader.PackageInfo, files []*ast.File) {
188+
if err := ctx.Err(); err != nil {
189+
return
190+
}
191+
afterTypeCheck(pkg, files)
192+
},
153193
}
154194
for _, path := range pkgs {
155195
conf.Import(path)
@@ -161,6 +201,10 @@ func (h *LangHandler) workspaceRefsTypecheck(ctx context.Context, bctx *build.Co
161201
return nil, err
162202
}
163203

204+
if err := ctx.Err(); err != nil {
205+
return nil, err
206+
}
207+
164208
// Publish typechecking error diagnostics.
165209
diags, err := errsToDiagnostics(typeErrs, prog)
166210
if err != nil {
@@ -179,6 +223,9 @@ func (h *LangHandler) workspaceRefsTypecheck(ctx context.Context, bctx *build.Co
179223
// workspaceRefsFromPkg collects all the references made to dependencies from
180224
// the specified package and returns the results.
181225
func (h *LangHandler) workspaceRefsFromPkg(ctx context.Context, bctx *build.Context, conn JSONRPC2Conn, params lspext.WorkspaceReferencesParams, fs *token.FileSet, pkg *loader.PackageInfo, rootPath string, results *refResultSorter) (err error) {
226+
if err := ctx.Err(); err != nil {
227+
return err
228+
}
182229
span, ctx := opentracing.StartSpanFromContext(ctx, "workspaceRefsFromPkg")
183230
defer func() {
184231
if err != nil {

0 commit comments

Comments
 (0)