如何在 spring 启动时禁用 Hazelcast 的默认关闭钩子

How to disable default shutdown hook of Hazelcast in spring boot

我正在使用 Hazelcast 开发网络套接字应用程序来共享在线用户的状态。一切工作正常,除了一件事,当其中一个应用程序实例关闭或重新启动时,连接到该实例的所有用户都断开连接并且 MessagingHandlerafterConnectionClosed 扩展 BinaryWebSocketHandler。在 afterConnectionClosed 中,连接到当前节点的用户的状态将被更新,这些状态在 Hazelcast 中。因此,当它尝试从 Hazelcast 中删除状态时,会出现以下错误:

com.hazelcast.core.HazelcastInstanceNotActiveException: State: SHUT_DOWN Operation: class com.hazelcast.map.impl.operation.RemoveOperation
        at com.hazelcast.spi.impl.operationservice.impl.Invocation.engineActive(Invocation.java:490)
        at com.hazelcast.spi.impl.operationservice.impl.Invocation.doInvoke(Invocation.java:523)
        at com.hazelcast.spi.impl.operationservice.impl.Invocation.invoke0(Invocation.java:513)
        at com.hazelcast.spi.impl.operationservice.impl.Invocation.invoke(Invocation.java:207)
        at com.hazelcast.spi.impl.operationservice.impl.InvocationBuilderImpl.invoke(InvocationBuilderImpl.java:60)
        at com.hazelcast.map.impl.proxy.MapProxySupport.invokeOperation(MapProxySupport.java:423)
        at com.hazelcast.map.impl.proxy.MapProxySupport.removeInternal(MapProxySupport.java:563)
        at com.hazelcast.map.impl.proxy.MapProxyImpl.remove(MapProxyImpl.java:207)
        at com.nisheeth.spring.MessageHandler.afterConnectionClosed(MessageHandler.java:57)
        at org.springframework.web.socket.handler.WebSocketHandlerDecorator.afterConnectionClosed(WebSocketHandlerDecorator.java:85)
        at org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator.afterConnectionClosed(LoggingWebSocketHandlerDecorator.java:72)
        at org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator.afterConnectionClosed(ExceptionWebSocketHandlerDecorator.java:78)
        at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.onClose(StandardWebSocketHandlerAdapter.java:141)
        at org.apache.tomcat.websocket.WsSession.fireEndpointOnClose(WsSession.java:535)
        at org.apache.tomcat.websocket.WsSession.doClose(WsSession.java:481)
        at org.apache.tomcat.websocket.WsSession.close(WsSession.java:445)
        at org.apache.tomcat.websocket.WsWebSocketContainer.destroy(WsWebSocketContainer.java:960)
        at org.apache.tomcat.websocket.server.WsContextListener.contextDestroyed(WsContextListener.java:48)
        at org.apache.catalina.core.StandardContext.listenerStop(StandardContext.java:4792)
        at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5429)
        at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:226)
        at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1435)
        at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1424)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)
        at ------ submitted from ------.(Unknown Source)
        at com.hazelcast.spi.impl.operationservice.impl.InvocationFuture.resolve(InvocationFuture.java:127)
        at com.hazelcast.spi.impl.operationservice.impl.InvocationFuture.resolveAndThrowIfException(InvocationFuture.java:79)
        at com.hazelcast.spi.impl.AbstractInvocationFuture.get(AbstractInvocationFuture.java:147)
        at com.hazelcast.map.impl.proxy.MapProxySupport.invokeOperation(MapProxySupport.java:424)
        at com.hazelcast.map.impl.proxy.MapProxySupport.removeInternal(MapProxySupport.java:563)
        at com.hazelcast.map.impl.proxy.MapProxyImpl.remove(MapProxyImpl.java:207)
        at com.nisheeth.spring.MessageHandler.afterConnectionClosed(MessageHandler.java:57)
        at org.springframework.web.socket.handler.WebSocketHandlerDecorator.afterConnectionClosed(WebSocketHandlerDecorator.java:85)
        at org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator.afterConnectionClosed(LoggingWebSocketHandlerDecorator.java:72)
        at org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator.afterConnectionClosed(ExceptionWebSocketHandlerDecorator.java:78)
        at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.onClose(StandardWebSocketHandlerAdapter.java:141)
        at org.apache.tomcat.websocket.WsSession.fireEndpointOnClose(WsSession.java:535)
        at org.apache.tomcat.websocket.WsSession.doClose(WsSession.java:481)
        at org.apache.tomcat.websocket.WsSession.close(WsSession.java:445)
        at org.apache.tomcat.websocket.WsWebSocketContainer.destroy(WsWebSocketContainer.java:960)
        at org.apache.tomcat.websocket.server.WsContextListener.contextDestroyed(WsContextListener.java:48)
        at org.apache.catalina.core.StandardContext.listenerStop(StandardContext.java:4792)
        at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5429)
        at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:226)
        at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1435)
        at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1424)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

我正在使用以下属性禁用默认关机:

config.setProperty(GroupProperty.SHUTDOWNHOOK_ENABLED.getName(), "false");
config.setProperty(GroupProperty.SHUTDOWNHOOK_POLICY.getName(), "GRACEFUL");

但在用户断开连接之前它仍然处于关闭状态。有没有办法以在应用程序结束时关闭 hazelcast 的方式配置 hazelcast?

@nisheeth-shah,这更像是一个 Spring 相关的问题,因为它 Spring 决定了 bean 的关闭顺序。

你可以做什么,你可以用 @DependsOn 注释来注释你的 MessageHandler bean 并给出 HazelcastInstance bean 的名称,就像这样 @DependsOn("hazelcastInstance")。请参阅此 link 以获取解释。基本上,Spring 将在创建 MessageHandler 之前启动 HazelcastInstance,并且不会在 MessageHandler bean 销毁之前关闭 HazelcastInstance

此外,不要禁用 Hazelcast 关闭钩子。

我一直在尝试不同的方法来处理正常关闭 spring websocket 连接,这也修改了在线用户的 hazelcast 地图,但是 none 有效。我终于使用了 SmartLifecycle 接口。 class 的文档可以在 here.

中找到

这是我用于正确关机的代码。是的,它在 Hazelcast 关闭之前被调用:

@Component
public class AppLifecycle implements SmartLifecycle {

    private Logger log = LoggerFactory.getLogger(AppLifecycle.class);

    @Autowired
    private SampleService sampleService;

    @Override

    public boolean isAutoStartup() {
        log.debug("=========================auto startup=========================");
        return true;
    }

    @Override
    public void stop(Runnable runnable) {
        sampleService.getSessionMap().forEach((key, session) -> {
            try {
                session.close(CloseStatus.SERVICE_RESTARTED);
                log.debug("disconnecting : {}", key);
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        });
        log.debug("=========================stop runnable=========================");
        new Thread(runnable).start();
    }

    @Override
    public void start() {
        log.debug("=========================start=========================");
    }

    @Override
    public void stop() {
        log.debug("=========================stop=========================");
    }

    @Override
    public boolean isRunning() {
        return true;
    }

    @Override
    public int getPhase() {
        return Integer.MAX_VALUE;
    }
}

您可以在 @PreDestroy 中使用 hazelcastInstance.shutdown()

@PreDestroy
public void shutDownHazelcast(){
        hazelcastInstance.shutdown()
}

这将正常关闭 hazelcast 实例