Skip to content

Commit d2950be

Browse files
committed
Working
1 parent 251c938 commit d2950be

File tree

6 files changed

+30
-14
lines changed

6 files changed

+30
-14
lines changed

load-tests/self/src/main/java/io/fusionauth/http/load/LoadHandler.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ private void handleLoad(HTTPRequest req, HTTPResponse res) {
131131
}
132132

133133
private void handleNoOp(HTTPRequest req, HTTPResponse res) {
134-
// Note that it is intentionally that we are not reading the InputStream. This will cause the server to have to drain it.
135134
try (InputStream is = req.getInputStream()) {
136135
// Just read the bytes from the InputStream and return. Do no other worker.
137136
is.readAllBytes();

load-tests/self/src/main/java/io/fusionauth/http/load/Main.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public static void main(String[] args) throws Exception {
4141

4242
try (HTTPServer ignore = new HTTPServer().withHandler(new LoadHandler())
4343
.withCompressByDefault(false)
44+
.withMaxRequestsPerConnection(100_000_000)
4445
.withInitialReadTimeout(Duration.ofSeconds(10))
4546
.withMinimumReadThroughput(4 * 1024)
4647
.withMinimumWriteThroughput(4 * 1024)

load-tests/self/src/main/script/start.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,5 @@ if [[ $# -ge 1 && $1 == "--suspend" ]]; then
4141
shift
4242
fi
4343

44+
ulimit -S -n 32768
4445
~/dev/java/current21/bin/java ${suspend} -cp "${CLASSPATH}" -Dio.fusionauth.http.server.stats="${SCRIPT_DIR}" io.fusionauth.http.load.Main

load-tests/tomcat/src/main/java/io/fusionauth/http/load/LoadServlet.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ private void handleLoad(HttpServletRequest req, HttpServletResponse res) {
137137
}
138138

139139
private void handleNoOp(HttpServletRequest req, HttpServletResponse res) {
140-
// Note that it is intentionally that we are not reading the InputStream. This will cause the server to have to drain it.
141140
try (InputStream is = req.getInputStream()) {
142141
// Just read the bytes from the InputStream and return. Do no other worker.
143142
is.readAllBytes();

src/main/java/io/fusionauth/http/server/internal/HTTPServerThread.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ public void run() {
107107
logger.trace("[{}] Accepted inbound connection. [{}] existing connections.", listenerAddress, clients.size());
108108
}
109109

110+
// TODO : Daniel : Review : Why is this number so much higher than the worker count when using persistent connections?
111+
// When using RESTIFY - we kill a lot of connections because read returns -1 while waiting for preamble.
112+
// This causes us to close a lot of workers. When using the JDK REST client this doesn't happen.
113+
// I don't know if this is just working as designed for HTTPURLConnection, or if it is related to
114+
// the read ahead we are doing.
115+
// Show Brian to see if he has any ideas.
110116
if (instrumenter != null) {
111117
instrumenter.acceptedConnection();
112118
}
@@ -187,8 +193,18 @@ public void run() {
187193
ClientInfo client = iterator.next();
188194
Thread thread = client.thread();
189195
long threadId = thread.threadId();
190-
if (!thread.isAlive()) {
191-
logger.trace("[{}] Remove dead client worker. Born [{}]. Died at age [{}] ms. Requests handled [{}].", threadId, client.getStartInstant(), client.getAge(), client.getHandledRequests());
196+
boolean threadIsAlive = thread.isAlive();
197+
var threadState = thread.getState();
198+
if (threadState == Thread.State.TERMINATED) {
199+
if (threadIsAlive) {
200+
System.out.println("[" + threadId + "] is alive in state [" + threadState + "]");
201+
}
202+
} else if (!threadIsAlive) {
203+
System.out.println("[" + threadId + "] is dead in state [" + threadState + "]");
204+
}
205+
206+
if (!threadIsAlive) {
207+
logger.debug("[{}] Remove dead client worker. Thread state [{}] Born [{}]. Died at age [{}] ms. Requests handled [{}].", threadId, threadState, client.getStartInstant(), client.getAge(), client.getHandledRequests());
192208
iterator.remove();
193209
removedClientCount++;
194210
continue;

src/main/java/io/fusionauth/http/server/internal/HTTPWorker.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
import java.net.SocketTimeoutException;
2323

2424
import io.fusionauth.http.ConnectionClosedException;
25-
import io.fusionauth.http.server.HTTPRequest;
26-
import io.fusionauth.http.server.HTTPResponse;
2725
import io.fusionauth.http.HTTPValues;
2826
import io.fusionauth.http.HTTPValues.Connections;
2927
import io.fusionauth.http.HTTPValues.Headers;
@@ -34,6 +32,8 @@
3432
import io.fusionauth.http.log.Logger;
3533
import io.fusionauth.http.server.HTTPHandler;
3634
import io.fusionauth.http.server.HTTPListenerConfiguration;
35+
import io.fusionauth.http.server.HTTPRequest;
36+
import io.fusionauth.http.server.HTTPResponse;
3737
import io.fusionauth.http.server.HTTPServerConfiguration;
3838
import io.fusionauth.http.server.Instrumenter;
3939
import io.fusionauth.http.server.io.HTTPInputStream;
@@ -69,8 +69,6 @@ public class HTTPWorker implements Runnable {
6969

7070
private final Throughput throughput;
7171

72-
// TODO : Daniel : Review : Services such as Apache Tomcat have a maximum number of requests per keep-alive to protect against DOS attacks.
73-
// Needs more investigation, but we could cap the duration of worker by time or number of requests.
7472
private long handledRequests;
7573

7674
private volatile State state;
@@ -130,6 +128,7 @@ public void run() {
130128
// Daniel : Is there a risk of the preamble not needing the entire set of left over bytes and it trying to push
131129
// back bytes from it's own buffer? This would fail because we check that buffer is null when calling push.
132130
// But it would cause this request to fail.
131+
133132
inputStream.setDelegate(new ThroughputInputStream(socket.getInputStream(), throughput));
134133

135134
// Not this line of code will block
@@ -198,6 +197,7 @@ public void run() {
198197
if (!keepSocketAlive) {
199198
logger.trace("[{}] Closing socket. No Keep-Alive.", Thread.currentThread().threadId());
200199
closeSocketOnly(CloseSocketReason.Expected);
200+
return;
201201
}
202202

203203
// Transition to Keep-Alive state and reset the SO timeout
@@ -235,8 +235,8 @@ public void run() {
235235
logger.debug("[{}] Closing socket [{}]. {}.", Thread.currentThread().threadId(), state, message);
236236
}
237237
closeSocketOnly(reason);
238-
} catch (ParseException pe) {
239-
logger.info("[{}] Closing socket with status [{}]. Bad request, failed to parse request. Reason [{}] Parser state [{}]", Thread.currentThread().threadId(), Status.BadRequest, pe.getMessage(), pe.getState());
238+
} catch (ParseException e) {
239+
logger.debug("[{}] Closing socket with status [{}]. Bad request, failed to parse request. Reason [{}] Parser state [{}]", Thread.currentThread().threadId(), Status.BadRequest, e.getMessage(), e.getState());
240240
closeSocketOnError(response, Status.BadRequest);
241241
} catch (SocketException e) {
242242
// This should only happen when the server is shutdown and this thread is waiting to read or write. In that case, this will throw a
@@ -246,13 +246,13 @@ public void run() {
246246
logger.debug("[{}] Closing socket. Server is shutting down.", Thread.currentThread().threadId());
247247
closeSocketOnly(CloseSocketReason.Expected);
248248
}
249-
} catch (IOException io) {
250-
logger.debug(String.format("[%s] Closing socket with status [%d]. An IO exception was thrown during processing. These are pretty common.", Thread.currentThread().threadId(), Status.InternalServerError), io);
249+
} catch (IOException e) {
250+
logger.debug(String.format("[%s] Closing socket with status [%d]. An IO exception was thrown during processing. These are pretty common.", Thread.currentThread().threadId(), Status.InternalServerError), e);
251251
closeSocketOnError(response, Status.InternalServerError);
252-
} catch (Throwable t) {
252+
} catch (Throwable e) {
253253
// Log the error and signal a failure
254254
var status = Status.InternalServerError;
255-
logger.error(String.format("[%s] Closing socket with status [%d]. An HTTP worker threw an exception while processing a request.", Thread.currentThread().threadId(), status), t);
255+
logger.error(String.format("[%s] Closing socket with status [%d]. An HTTP worker threw an exception while processing a request.", Thread.currentThread().threadId(), status), e);
256256
closeSocketOnError(response, status);
257257
} finally {
258258
if (instrumenter != null) {

0 commit comments

Comments
 (0)