Java SpringContextShutdownHook防止JVM关闭

Java SpringContextShutdownHook防止JVM关闭,java,jvm,project-reactor,Java,Jvm,Project Reactor,当我SIGTERMJVM时,我有一个反应式应用程序的行为有点奇怪。基本上,JVM无法正常退出,因为其中一个关机挂钩似乎被卡住了。当我SIGTERM时,我看到以下日志: {"timeStamp":"2021-04-14T19:52:44.472+05:30","message":"Shutting down ExecutorService 'applicationTaskExecutor'","logger&

当我
SIGTERM
JVM时,我有一个反应式应用程序的行为有点奇怪。基本上,
JVM
无法正常退出,因为其中一个关机挂钩似乎被卡住了。当我
SIGTERM
时,我看到以下日志:

{"timeStamp":"2021-04-14T19:52:44.472+05:30","message":"Shutting down ExecutorService 'applicationTaskExecutor'","logger":"org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor","thread":"SpringContextShutdownHook","level":"INFO"}
这之后什么都没有
VisualVM
显示此线程(
SpringContextShutdownHook
)处于start
Park
状态

  @EventListener(ApplicationReadyEvent.class)
  public void poll() {
    String queueUrl =
        String.format("%s/%s", properties.getSqs().getHost(), properties.getSqs().getQueue());

    ReceiveMessageRequest request =
        new ReceiveMessageRequest()
            .withQueueUrl(queueUrl)
            .withMaxNumberOfMessages(
                properties.getSqs().getClientConfiguration().getMaxNoOfMessages());

    RetryBackoffSpec retryStrategy =
        Retry.backoff(
                Long.MAX_VALUE,
                Duration.ofMillis(properties.getSqs().getClientConfiguration().getInitialBackoff()))
            .jitter(properties.getSqs().getClientConfiguration().getJitter());

    Flux.<List<Message>>generate(
            sink -> {
              List<Message> messages = client.receiveMessage(request).getMessages();
              sink.next(messages);
            })
        .subscribeOn(Schedulers.boundedElastic())
        .retryWhen(retryStrategy)
        .flatMap(messages -> Flux.fromIterable(messages).subscribeOn(Schedulers.parallel()))
        .map(
            message ->
                Pair.of(message, convertor.deserialize(message.getBody(), BackendEvent.class)))
        .flatMap(
            pair -> {
              Event event = pair.getRight();
              EventInfo eventInfo = event.getEventInfo();
              return factory
                  .getHandler(event)
                  .handle(pair.getRight())
                  .map(ignored -> pair.getLeft())
                  .onErrorResume(
                      err -> Mono.just(pair.getLeft())); // todo: handle failed messages using DLQs
            })
        .publishOn(Schedulers.boundedElastic())
        .doOnNext(
            message ->
                client.deleteMessage(
                    new DeleteMessageRequest().withReceiptHandle(message.getReceiptHandle())))
        .blockLast();
  }
@EventListener(ApplicationReadyEvent.class)
公众投票{
字符串队列URL=
String.format(“%s/%s”、properties.getSqs().getHost()、properties.getSqs().getQueue());
ReceiveMessageRequest请求=
新的ReceiveMessageRequest()
.withQueueUrl(queueUrl)
.withMaxNumberOfMessages(
getSqs().getClientConfiguration().getMaxNoOfMessages());
RetryBackoffSpec retryStrategy=
重试。退避(
Long.MAX_值,
持续时间(properties.getSqs().getClientConfiguration().getInitialBackoff())
.jitter(properties.getSqs().getClientConfiguration().getJitter());
通量生成(
水槽->{
List messages=client.receiveMessage(request.getMessages();
sink.next(消息);
})
.subscribeOn(Schedulers.BoundedElistic())
.retryWhen(retryStrategy)
.flatMap(messages->Flux.fromIterable(messages).subscribeOn(Schedulers.parallel())
.地图(
信息->
对(message,convertor.deserialize(message.getBody(),BackendEvent.class)))
.平面图(
配对->{
Event=pair.getRight();
EventInfo EventInfo=event.getEventInfo();
返回工厂
.getHandler(事件)
.handle(pair.getRight())
.map(忽略->pair.getLeft())
A.简历(
err->Mono.just(pair.getLeft());//todo:使用DLQ处理失败的消息
})
.publishOn(Schedulers.boundedElastic())
doOnNext先生(
信息->
client.deleteMessage(
新建DeleteMessageRequest().withReceiptHandle(message.getReceiptHandle()))
.blockLast();
}
VisualVM
输出:


获取线程转储并查看非守护进程线程的堆栈跟踪。