Skip to content

Commit 57cc0b4

Browse files
committed
Do not timeout on connecting to the server if waitForDebugger is set
1 parent df3d53f commit 57cc0b4

File tree

1 file changed

+41
-37
lines changed

1 file changed

+41
-37
lines changed

src/lsptoolshost/roslynLanguageServer.ts

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -590,63 +590,67 @@ export class RoslynLanguageServer {
590590
const result: string = isString(data) ? data : data.toString(RoslynLanguageServer.encoding);
591591
_channel.append('[stderr] ' + result);
592592
});
593+
childProcess.on('exit', (code) => {
594+
_channel.appendLine(`Language server process exited with ${code}`);
595+
});
593596

594597
// Timeout promise used to time out the connection process if it takes too long.
595-
const timeout = new Promise<undefined>((resolve, reject) => {
598+
const timeout = new Promise<undefined>((resolve) => {
596599
RAL().timer.setTimeout(resolve, languageServerOptions.startTimeout);
600+
});
597601

602+
const connectionPromise = new Promise<net.Socket>((resolveConnection, rejectConnection) => {
598603
// If the child process exited unexpectedly, reject the promise early.
599604
// Error information will be captured from the stdout/stderr streams above.
600605
childProcess.on('exit', (code) => {
601606
if (code && code !== 0) {
602-
const message = `Language server process exited with ${code}`;
603-
_channel.appendLine(message);
604-
reject(new Error(message));
607+
rejectConnection(new Error('Language server process exited unexpectedly'));
605608
}
606609
});
607-
});
608610

609-
// The server process will create the named pipe used for communication. Wait for it to be created,
610-
// and listen for the server to pass back the connection information via stdout.
611-
const namedPipeConnectionPromise = new Promise<NamedPipeInformation>((resolve) => {
612-
_channel.appendLine('waiting for named pipe information from server...');
613-
childProcess.stdout.on('data', (data: { toString: (arg0: any) => any }) => {
614-
const result: string = isString(data) ? data : data.toString(RoslynLanguageServer.encoding);
615-
// Use the regular expression to find all JSON lines
616-
const jsonLines = result.match(RoslynLanguageServer.namedPipeKeyRegex);
617-
if (jsonLines) {
618-
const transmittedPipeNameInfo: NamedPipeInformation = JSON.parse(jsonLines[0]);
619-
_channel.appendLine('received named pipe information from server');
620-
resolve(transmittedPipeNameInfo);
621-
}
611+
// The server process will create the named pipe used for communication. Wait for it to be created,
612+
// and listen for the server to pass back the connection information via stdout.
613+
const namedPipePromise = new Promise<NamedPipeInformation>((resolve) => {
614+
_channel.appendLine('waiting for named pipe information from server...');
615+
childProcess.stdout.on('data', (data: { toString: (arg0: any) => any }) => {
616+
const result: string = isString(data) ? data : data.toString(RoslynLanguageServer.encoding);
617+
// Use the regular expression to find all JSON lines
618+
const jsonLines = result.match(RoslynLanguageServer.namedPipeKeyRegex);
619+
if (jsonLines) {
620+
const transmittedPipeNameInfo: NamedPipeInformation = JSON.parse(jsonLines[0]);
621+
_channel.appendLine('received named pipe information from server');
622+
resolve(transmittedPipeNameInfo);
623+
}
624+
});
622625
});
623-
});
624626

625-
// Wait for the server to send back the name of the pipe to connect to.
626-
// If it takes too long it will timeout and throw an error.
627-
const pipeConnectionInfo = await Promise.race([namedPipeConnectionPromise, timeout]);
628-
if (pipeConnectionInfo === undefined) {
629-
throw new Error('Timeout. Named pipe information not received from server.');
630-
}
627+
const socketPromise = namedPipePromise.then(async (pipeConnectionInfo) => {
628+
return new Promise<net.Socket>((resolve, reject) => {
629+
_channel.appendLine('attempting to connect client to server...');
630+
const socket = net.createConnection(pipeConnectionInfo.pipeName, () => {
631+
_channel.appendLine('client has connected to server');
632+
resolve(socket);
633+
});
631634

632-
const socketPromise = new Promise<net.Socket>((resolve, reject) => {
633-
_channel.appendLine('attempting to connect client to server...');
634-
const socket = net.createConnection(pipeConnectionInfo.pipeName, () => {
635-
_channel.appendLine('client has connected to server');
636-
resolve(socket);
635+
// If we failed to connect for any reason, ensure the error is propagated.
636+
socket.on('error', (err) => reject(err));
637+
});
637638
});
638639

639-
// If we failed to connect for any reason, ensure the error is propagated.
640-
socket.on('error', (err) => reject(err));
640+
socketPromise.then(resolveConnection, rejectConnection);
641641
});
642642

643643
// Wait for the client to connect to the named pipe.
644-
// If it takes too long it will timeout and throw an error.
645-
const socket = await Promise.race([socketPromise, timeout]);
644+
let socket: net.Socket | undefined;
645+
if (commonOptions.waitForDebugger) {
646+
// Do not timeout the connection when the waitForDebugger option is set.
647+
socket = await connectionPromise;
648+
} else {
649+
socket = await Promise.race([connectionPromise, timeout]);
650+
}
651+
646652
if (socket === undefined) {
647-
throw new Error(
648-
'Timeout. Client cound not connect to server via named pipe: ' + pipeConnectionInfo.pipeName
649-
);
653+
throw new Error('Timeout. Client cound not connect to server via named pipe');
650654
}
651655

652656
return {

0 commit comments

Comments
 (0)