Skip to content

Commit 59b7d65

Browse files
committed
Jetty HTTP Container native timeout
Signed-off-by: Maxim Nesen <maxim.nesen@oracle.com>
1 parent 28fe57f commit 59b7d65

File tree

1 file changed

+10
-41
lines changed

1 file changed

+10
-41
lines changed

containers/jetty-http/src/main/java17/org/glassfish/jersey/jetty/JettyHttpContainer.java

+10-41
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.eclipse.jetty.security.AuthenticationState;
4747
import org.eclipse.jetty.server.Handler;
4848
import org.eclipse.jetty.util.Callback;
49+
import org.eclipse.jetty.util.thread.Scheduler;
4950
import org.glassfish.jersey.internal.MapPropertiesDelegate;
5051
import org.glassfish.jersey.internal.inject.AbstractBinder;
5152
import org.glassfish.jersey.internal.inject.ReferencingFactory;
@@ -91,8 +92,6 @@ public final class JettyHttpContainer extends Handler.Abstract implements Contai
9192
*/
9293
private boolean configSetStatusOverSendError;
9394

94-
private final ScheduledThreadPoolExecutor timeoutScheduler;
95-
9695
/**
9796
* Referencing factory for Jetty request.
9897
*/
@@ -141,7 +140,7 @@ protected void configure() {
141140
@Override
142141
public boolean handle(Request request, Response response, Callback callback) throws Exception {
143142

144-
final ResponseWriter responseWriter = new ResponseWriter(timeoutScheduler, request, response, callback, configSetStatusOverSendError);
143+
final ResponseWriter responseWriter = new ResponseWriter(request, response, callback, configSetStatusOverSendError);
145144
try {
146145
LOGGER.debugLog(LocalizationMessages.CONTAINER_STARTED());
147146
final URI baseUri = getBaseUri(request);
@@ -253,37 +252,38 @@ private String getBasePath(final Request request) {
253252
}
254253
}
255254

256-
private static final class ResponseWriter implements ContainerResponseWriter {
255+
private static class ResponseWriter implements ContainerResponseWriter {
257256

258257
private final Request request;
259258
private final Response response;
260259
private final Callback callback;
261260
private final boolean configSetStatusOverSendError;
262261
private final long asyncStartTimeNanos;
263-
private final ScheduledExecutorService timeoutScheduler;
262+
private final Scheduler scheduler;
264263
private final ConcurrentLinkedQueue<TimeoutHandler> timeoutHandlerQueue = new ConcurrentLinkedQueue<>();
265-
private ScheduledFuture<?> currentTimerTask;
264+
private Scheduler.Task currentTimerTask;
266265

267-
ResponseWriter(final ScheduledExecutorService timeoutScheduler, final Request request, final Response response,
266+
ResponseWriter(final Request request, final Response response,
268267
final Callback callback, final boolean configSetStatusOverSendError) {
269-
this.timeoutScheduler = timeoutScheduler;
270268
this.request = request;
271269
this.response = response;
272270
this.callback = callback;
273271
this.asyncStartTimeNanos = System.nanoTime();
274272
this.configSetStatusOverSendError = configSetStatusOverSendError;
273+
274+
this.scheduler = request.getComponents().getScheduler();
275275
}
276276

277277
private synchronized void setNewTimeout(long timeOut, TimeUnit timeUnit) {
278278
long timeOutNanos = timeUnit.toNanos(timeOut);
279279
if (currentTimerTask != null) {
280280
// Do not interrupt, see callTimeoutHandlers()
281-
currentTimerTask.cancel(false);
281+
currentTimerTask.cancel();
282282
}
283283
// Use System.nanoTime() as the clock source here, because the returned value is not prone to wall-clock
284284
// drift - unlike System.currentTimeMillis().
285285
long delayNanos = Math.max(asyncStartTimeNanos - System.nanoTime() + timeOutNanos, 0L);
286-
currentTimerTask = timeoutScheduler.schedule(this::callTimeoutHandlers, delayNanos, TimeUnit.NANOSECONDS);
286+
currentTimerTask = scheduler.schedule(this::callTimeoutHandlers, delayNanos, TimeUnit.NANOSECONDS);
287287
}
288288

289289
private void callTimeoutHandlers() {
@@ -437,50 +437,21 @@ public void doStop() throws Exception {
437437
appHandler.onShutdown(this);
438438
appHandler = null;
439439

440-
timeoutScheduler.shutdown();
441440
boolean needInterrupt = false;
442-
while (true) {
443-
try {
444-
if (timeoutScheduler.awaitTermination(1L, TimeUnit.MINUTES)) {
445-
break;
446-
}
447-
} catch (InterruptedException e) {
448-
if (!needInterrupt) {
449-
needInterrupt = true;
450-
timeoutScheduler.shutdownNow();
451-
}
452-
}
453-
}
454441
if (needInterrupt) {
455442
Thread.currentThread().interrupt();
456443
}
457444
}
458445

459446
private static final AtomicInteger TIMEOUT_HANDLER_ID_GEN = new AtomicInteger();
460447

461-
private static ScheduledThreadPoolExecutor createTimeoutScheduler() {
462-
// Note: creating the thread-pool does not start the core-pool threads.
463-
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, r -> {
464-
Thread t = new Thread(r, "JettyHttpContainer-Timeout-Handler #" + TIMEOUT_HANDLER_ID_GEN.incrementAndGet());
465-
t.setDaemon(true);
466-
return t;
467-
});
468-
// Limit the number of timeout handling threads to a quarter of the number of CPUs, at least 2.
469-
executor.setMaximumPoolSize(Math.max(2, Runtime.getRuntime().availableProcessors() / 4));
470-
executor.allowCoreThreadTimeOut(true);
471-
// Don't Keep timeout handling threads around "forever".
472-
executor.setKeepAliveTime(100, TimeUnit.MILLISECONDS);
473-
return executor;
474-
}
475-
476448
/**
477449
* Create a new Jetty HTTP container.
478450
*
479451
* @param application JAX-RS / Jersey application to be deployed on Jetty HTTP container.
480452
* @param parentContext DI provider specific context with application's registered bindings.
481453
*/
482454
JettyHttpContainer(final Application application, final Object parentContext) {
483-
this.timeoutScheduler = createTimeoutScheduler();
484455
this.appHandler = new ApplicationHandler(application, new JettyBinder(), parentContext);
485456
}
486457

@@ -490,7 +461,6 @@ private static ScheduledThreadPoolExecutor createTimeoutScheduler() {
490461
* @param application JAX-RS / Jersey application to be deployed on Jetty HTTP container.
491462
*/
492463
JettyHttpContainer(final Application application) {
493-
this.timeoutScheduler = createTimeoutScheduler();
494464
this.appHandler = new ApplicationHandler(application, new JettyBinder());
495465

496466
cacheConfigSetStatusOverSendError();
@@ -502,7 +472,6 @@ private static ScheduledThreadPoolExecutor createTimeoutScheduler() {
502472
* @param applicationClass JAX-RS / Jersey class of application to be deployed on Jetty HTTP container.
503473
*/
504474
JettyHttpContainer(final Class<? extends Application> applicationClass) {
505-
this.timeoutScheduler = createTimeoutScheduler();
506475
this.appHandler = new ApplicationHandler(applicationClass, new JettyBinder());
507476

508477
cacheConfigSetStatusOverSendError();

0 commit comments

Comments
 (0)