Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jetty 12 graceful contexts #9867

Merged
merged 11 commits into from
Jun 7, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
Expand Down Expand Up @@ -54,7 +53,6 @@
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.component.ClassLoaderDump;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.component.Graceful;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
Expand All @@ -63,14 +61,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ContextHandler extends Handler.Wrapper implements Attributes, Graceful, AliasCheck
public class ContextHandler extends Handler.Wrapper implements Attributes, AliasCheck
{
// TODO where should the alias checking go?
// TODO add protected paths to ServletContextHandler?
// TODO what about ObjectFactory stuff
// TODO what about a Context logger?
// TODO init param stuff to ServletContextHandler

private static final Logger LOG = LoggerFactory.getLogger(ContextHandler.class);
private static final ThreadLocal<Context> __context = new ThreadLocal<>();

Expand Down Expand Up @@ -147,10 +139,9 @@ public static String getServerInfo()
public enum Availability
{
STOPPED, // stopped and can't be made unavailable nor shutdown
STARTING, // starting inside of doStart. It may go to any of the next states.
STARTING, // starting inside doStart. It may go to any of the next states.
AVAILABLE, // running normally
UNAVAILABLE, // Either a startup error or explicit call to setAvailable(false)
SHUTDOWN, // graceful shutdown
}

/**
Expand Down Expand Up @@ -583,29 +574,6 @@ protected void notifyExitScope(Request request)
}
}

/**
* @return true if this context is shutting down
*/
@ManagedAttribute("true for graceful shutdown, which allows existing requests to complete")
public boolean isShutdown()
{
// TODO
return false;
}

/**
* Set shutdown status. This field allows for graceful shutdown of a context. A started context may be put into non accepting state so that existing
* requests can complete, but no new requests are accepted.
*/
@Override
public CompletableFuture<Void> shutdown()
{
// TODO
CompletableFuture<Void> completableFuture = new CompletableFuture<>();
completableFuture.complete(null);
return completableFuture;
}

/**
* @return false if this context is unavailable (sends 503)
*/
Expand Down Expand Up @@ -651,15 +619,16 @@ public void setAvailable(boolean available)
Availability availability = _availability.get();
switch (availability)
{
case STARTING:
case AVAILABLE:
if (!_availability.compareAndSet(availability, Availability.UNAVAILABLE))
continue;
break;
default:
break;
case STARTING, AVAILABLE ->
{
if (_availability.compareAndSet(availability, Availability.UNAVAILABLE))
return;
}
default ->
{
return;
}
}
break;
}
}
}
Expand Down Expand Up @@ -1160,14 +1129,6 @@ public <H extends ContextHandler> H getContextHandler()
return (H)ContextHandler.this;
}

@Override
public Object getAttribute(String name)
{
// TODO the Attributes.Layer is a little different to previous
// behaviour. We need to verify if that is OK
return super.getAttribute(name);
}

@Override
public Request.Handler getErrorHandler()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.CountingCallback;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.component.Graceful;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -32,24 +34,30 @@ public class GracefulHandler extends Handler.Wrapper implements Graceful
{
private static final Logger LOG = LoggerFactory.getLogger(GracefulHandler.class);

private final LongAdder dispatchedStats = new LongAdder();
private final Shutdown shutdown;
private final LongAdder _requests = new LongAdder();
private final Shutdown _shutdown;

public GracefulHandler()
{
shutdown = new Shutdown(this)
_shutdown = new Shutdown(this)
{
@Override
public boolean isShutdownDone()
{
long count = dispatchedStats.sum();
long count = getCurrentRequestCount();
if (LOG.isDebugEnabled())
LOG.debug("isShutdownDone: count {}", count);
return count == 0;
}
};
}

@ManagedAttribute("number of requests being currently handled")
public long getCurrentRequestCount()
{
return _requests.sum();
}

/**
* Flag indicating that Graceful shutdown has been initiated.
*
Expand All @@ -59,7 +67,7 @@ public boolean isShutdownDone()
@Override
public boolean isShutdown()
{
return shutdown.isShutdown();
return _shutdown.isShutdown();
}

@Override
Expand All @@ -86,18 +94,18 @@ public boolean handle(Request request, Response response, Callback callback) thr
{
boolean handled = super.handle(request, response, shutdownCallback);
if (!handled)
shutdownCallback.decrement();
shutdownCallback.completed();
return handled;
}
catch (Throwable t)
{
shutdownCallback.decrement();
throw t;
Response.writeError(request, response, shutdownCallback, t);
return true;
}
finally
{
if (isShutdown())
shutdown.check();
_shutdown.check();
}
}

Expand All @@ -106,43 +114,28 @@ public CompletableFuture<Void> shutdown()
{
if (LOG.isDebugEnabled())
LOG.debug("Shutdown requested");
return shutdown.shutdown();
return _shutdown.shutdown();
}

private class ShutdownTrackingCallback extends Callback.Nested
private class ShutdownTrackingCallback extends CountingCallback
{
final Request request;
final Response response;

public ShutdownTrackingCallback(Request request, Response response, Callback callback)
{
super(callback);
super(callback, 1);
this.request = request;
this.response = response;
dispatchedStats.increment();
}

public void decrement()
{
dispatchedStats.decrement();
}

@Override
public void failed(Throwable x)
{
decrement();
super.failed(x);
if (isShutdown())
shutdown.check();
_requests.increment();
}

@Override
public void succeeded()
public void completed()
{
decrement();
super.succeeded();
_requests.decrement();
if (isShutdown())
shutdown.check();
_shutdown.check();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,11 @@ public class GracefulHandlerTest
{
private static final Logger LOG = LoggerFactory.getLogger(GracefulHandlerTest.class);
private Server server;
private ServerConnector connector;

public Server createServer(Handler handler) throws Exception
{
server = new Server();
connector = new ServerConnector(server, 1, 1);
ServerConnector connector = new ServerConnector(server, 1, 1);
connector.setIdleTimeout(10000);
connector.setShutdownIdleTimeout(1000);
connector.setPort(0);
Expand Down
Loading