Quarkus 关闭信号后如何接受 http 请求?
How to accept http requests after shutdown signal in Quarkus?
我试过这个:
void onShutdown(@Observes final ShutdownEvent event) throws InterruptedException {
log.infof("ShutdownEvent received, waiting for %s seconds before shutting down", shutdownWaitSeconds);
TimeUnit.SECONDS.sleep(shutdownWaitSeconds);
log.info("Continue shutting down");
}
但是在收到 ShutdownEvent
之后,Quarkus 已经用 503 响应了 http 请求。看起来这可以用 preShutdown
方法中的 ShutdownListener 来完成。我已经实现了这个监听器,但它还没有被调用。我如何注册 ShutdownListener
?
这里的用例是 OpenShift 向终止 pod 发送请求。
选项 1:创建 Quarkus 扩展
说明是here。 ShutdownController
是我自己的 class 实现 ShutdownListener
,我在 preShutdown
方法中睡觉。
class ShutdownControllerProcessor {
@BuildStep
FeatureBuildItem feature() {
return new FeatureBuildItem("shutdown-controller");
}
@BuildStep
ShutdownListenerBuildItem shutdownListener() {
// Called at build time. Default constructor will be called at runtime.
// Getting MethodNotFoundException when calling default constructor here.
return new ShutdownListenerBuildItem(new ShutdownController(10));
}
}
选项 2:修改 ShutdownRecorder private static final 字段
可以使用反射添加新的关闭侦听器。这是一个有点难看的解决方案。
registerIfNeeded()
需要在 Quarkus 启动后调用,例如在 @PostConstruct
.
后使用定时器 1 秒
@ApplicationScoped
public class ListenerRegisterer {
public void registerIfNeeded() {
try {
tryToRegister();
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
private void tryToRegister() throws NoSuchFieldException, IllegalAccessException {
final var field = ShutdownRecorder.class.getDeclaredField("shutdownListeners");
field.setAccessible(true);
final var listeners = (List<ShutdownListener>) field.get(null);
if (listeners != null && !listeners.toString().contains("ShutdownController")) {
listeners.add(new ShutdownController(10));
setFinalStatic(field, listeners);
}
}
private static void setFinalStatic(final Field field, final Object newValue) throws NoSuchFieldException, IllegalAccessException {
field.setAccessible(true);
final var modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
}
我试过这个:
void onShutdown(@Observes final ShutdownEvent event) throws InterruptedException {
log.infof("ShutdownEvent received, waiting for %s seconds before shutting down", shutdownWaitSeconds);
TimeUnit.SECONDS.sleep(shutdownWaitSeconds);
log.info("Continue shutting down");
}
但是在收到 ShutdownEvent
之后,Quarkus 已经用 503 响应了 http 请求。看起来这可以用 preShutdown
方法中的 ShutdownListener 来完成。我已经实现了这个监听器,但它还没有被调用。我如何注册 ShutdownListener
?
这里的用例是 OpenShift 向终止 pod 发送请求。
选项 1:创建 Quarkus 扩展
说明是here。 ShutdownController
是我自己的 class 实现 ShutdownListener
,我在 preShutdown
方法中睡觉。
class ShutdownControllerProcessor {
@BuildStep
FeatureBuildItem feature() {
return new FeatureBuildItem("shutdown-controller");
}
@BuildStep
ShutdownListenerBuildItem shutdownListener() {
// Called at build time. Default constructor will be called at runtime.
// Getting MethodNotFoundException when calling default constructor here.
return new ShutdownListenerBuildItem(new ShutdownController(10));
}
}
选项 2:修改 ShutdownRecorder private static final 字段
可以使用反射添加新的关闭侦听器。这是一个有点难看的解决方案。
registerIfNeeded()
需要在 Quarkus 启动后调用,例如在 @PostConstruct
.
@ApplicationScoped
public class ListenerRegisterer {
public void registerIfNeeded() {
try {
tryToRegister();
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
private void tryToRegister() throws NoSuchFieldException, IllegalAccessException {
final var field = ShutdownRecorder.class.getDeclaredField("shutdownListeners");
field.setAccessible(true);
final var listeners = (List<ShutdownListener>) field.get(null);
if (listeners != null && !listeners.toString().contains("ShutdownController")) {
listeners.add(new ShutdownController(10));
setFinalStatic(field, listeners);
}
}
private static void setFinalStatic(final Field field, final Object newValue) throws NoSuchFieldException, IllegalAccessException {
field.setAccessible(true);
final var modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
}