Skip to content

Commit

Permalink
Fix connection drops
Browse files Browse the repository at this point in the history
- Remove default connection timeout - nodejs/node#27558.
- Add client error listener.
  • Loading branch information
JeremyTCD committed Dec 6, 2019
1 parent 2f7a7b5 commit cdc946f
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 3 deletions.
30 changes: 27 additions & 3 deletions src/NodeJS/Javascript/Servers/OutOfProcess/Http/HttpServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,19 @@ patchLStat();
// Set by NodeJSProcessFactory
let projectDir = process.cwd();

// Create server
const server = http.createServer(serverOnRequestListener);

// In Node.js v13+ this is the default, however for earlier versions it is 120 seconds.
server.setTimeout(0);

// Send client error details to client for debugging
server.on('clientError', serverOnClientError);

// Start server
const server = http.createServer((req, res) => {
server.listen(parseInt(args.port), 'localhost', serverOnListeningListener);

function serverOnRequestListener(req, res) {
let bodyChunks = [];
req.
on('data', chunk => bodyChunks.push(chunk)).
Expand Down Expand Up @@ -158,12 +169,25 @@ const server = http.createServer((req, res) => {
respondWithError(res, error);
}
});
}).listen(parseInt(args.port), 'localhost', function () {
}

// Send error details to client for debugging - https://nodejs.org/api/http.html#http_event_clienterror
function serverOnClientError(error: Error, socket: stream.Duplex) {
let errorJson = JSON.stringify({
errorMessage: error.message,
errorStack: error.stack
});

let httpResponseMessage = `HTTP/1.1 500 Internal Server Error\r\nContent-Length: ${Buffer.byteLength(errorJson, 'utf8')}\r\nContent-Type: text/html\r\n\r\n${errorJson}`;
socket.end(httpResponseMessage);
}

function serverOnListeningListener() {
// Signal to HttpNodeHost which loopback IP address (IPv4 or IPv6) and port it should make its HTTP connections on
// and that we are ready to process invocations.
let info = server.address() as AddressInfo;
console.log(`[Jering.Javascript.NodeJS: Listening on IP - ${info.address} Port - ${info.port}]`);
});
}

function getTempIdentifier(invocationRequest: InvocationRequest): string {
if (invocationRequest.newCacheIdentifier == null) {
Expand Down
29 changes: 29 additions & 0 deletions test/NodeJS/HttpNodeJSServiceIntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
using System.Text.Json;
using System.Threading;
using Xunit;
using Xunit.Abstractions;
Expand Down Expand Up @@ -954,6 +958,31 @@ public static IEnumerable<object[]> AllInvokeMethods_ReceiveAndLogStderrOutput_D
};
}

[Fact]
public async void AllInvokeMethods_HandleHttpClientErrorsSuchAsMalformedRequests()
{
// Arrange
HttpNodeJSService testSubject = CreateHttpNodeJSService();
await testSubject.InvokeFromStringAsync("module.exports = callback => callback();").ConfigureAwait(false); // Starts the Node.js process
Uri dummyEndpoint = testSubject.Endpoint;
var dummyJsonService = new JsonService();

// Act
using (var dummyHttpClient = new HttpClient())
// Send a request with an invalid HTTP method. NodeJS drops the connection halfway through and fires the clientError event - https://nodejs.org/api/http.html#http_event_clienterror
using (var dummyHttpRequestMessage = new HttpRequestMessage(new HttpMethod("INVALID"), dummyEndpoint))
using (HttpResponseMessage dummyHttpResponseMessage = await dummyHttpClient.SendAsync(dummyHttpRequestMessage).ConfigureAwait(false))
using (Stream dummyStream = await dummyHttpResponseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false))
{
InvocationError result = await dummyJsonService.DeserializeAsync<InvocationError>(dummyStream).ConfigureAwait(false);

// Assert
Assert.Equal(HttpStatusCode.InternalServerError, dummyHttpResponseMessage.StatusCode);
Assert.False(string.IsNullOrWhiteSpace(result.ErrorMessage));
Assert.False(string.IsNullOrWhiteSpace(result.ErrorStack));
}
}

/// <summary>
/// Specify <paramref name="loggerStringBuilder"/> for access to all logging output.
/// </summary>
Expand Down

0 comments on commit cdc946f

Please sign in to comment.