heartbeat threads blocks process shutdown because its hashed-wheel-timer is non-daemon thread.
protected final Logger logger = LoggerFactory.getLogger(getClass());
    private final Server server;
    
    private int heartbeat;
    private int heartbeatTimeout;
    private AtomicBoolean closed = new AtomicBoolean(false);
    private HashedWheelTimer heartbeatTimer;
    public HeaderExchangeServer(Server server) {
        if (server == null) {
            throw new IllegalArgumentException("server == null");
        }
        this.server = server;
        this.heartbeat = server.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0);
        this.heartbeatTimeout = server.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3);
        if (heartbeatTimeout < heartbeat * 2) {
            throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2");
        }
        startHeartbeatTimer();
    }
    public Server getServer() {
        return server;
    }
    @Override
    public boolean isClosed() {
        return server.isClosed();