@Override
    public void close(CloseReason closeReason) {
        if (!isConnected() || connection.isDisposed()) {
            return;
        }
        super.close(closeReason);
        Mono<Void> mono = connection.sendObject(NotificationFactory.createBuffer(closeReason))
                .then()
                .doOnError(throwable -> {
                    if (!ThrowableUtil.isDisconnectedClientError(throwable)) {
                        LOGGER.error("Failed to send the close notification", throwable);
                    }
                })
                .retryWhen(RETRY_SEND_CLOSE_NOTIFICATION);
        if (closeTimeout.isZero()) {
            mono = mono.doFinally(signal -> close());
        } else if (!closeTimeout.isNegative()) {
            mono = mono.then(connection.onTerminate())
                    .timeout(closeTimeout, HashedWheelScheduler.getDaemon())
                    .onErrorComplete(TimeoutException.class)
                    .doFinally(signal -> close());
        }
        mono.subscribe(null, t -> {
            if (!ThrowableUtil.isDisconnectedClientError(t)) {
                LOGGER.error("Failed to send the close notification after ("
                        + RETRY_SEND_CLOSE_NOTIFICATION.maxAttempts
                        + ") attempts", t);
            }
        });
    }
It is acceptable that the method isn't thread-safe
turms-gateway/src/main/java/im/turms/gateway/access/client/tcp/TcpConnection.java