如何在Spring Boot中禁用Hazelcast的默认关闭挂钩

7

我正在使用Hazelcast开发web socket应用程序,用于共享在线用户的状态。除了一个问题,一切都运行良好,即当其中一个应用程序实例关闭或重新启动时,所有连接到该实例的用户都会断开连接,并且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)

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

shutdown.disable=true

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

但是仍然会在用户断开连接之前关闭。有没有一种方式可以配置Hazelcast,使Hazelcast在应用程序结束时关闭?

3个回答

5

我一直在尝试不同的方法来处理Spring WebSocket连接的优雅关闭,同时还要修改在线用户的Hazelcast Map,但都没有成功。最终,我使用了SmartLifecycle接口。关于这个类的文档可以在这里找到。

以下是我用于正确关闭的代码。是的,在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;
    }
}

2

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

您可以在MessageHandler bean上使用@DependsOn注释,并给出HazelcastInstance bean的名称,例如:@DependsOn("hazelcastInstance")。请参见此链接以了解说明。基本上,Spring将在创建MessageHandler之前启动HazelcastInstance,并且不会在销毁MessageHandler bean之前关闭HazelcastInstance

另外,请勿禁用Hazelcast的关闭钩子。


链接未按预期工作 - Ahmed Hasn.

0

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

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

这将优雅地关闭您的Hazelcast实例


完全不起作用。我尝试了这个选项。Hazelcast在用户正常断开连接之前关闭了。 - Nisheeth Shah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接