private boolean closeOrUpdateSession(UserSession session, long nowNanos) {
        if (!session.isOpen()) {
            return false;
        }
        // 1. Check whether to switch to UDP
        if (UdpRequestDispatcher.isEnabled()
                && session.supportsSwitchingToUdp()
                && session.isConnected()
                && nowNanos - session.getLastRequestTimestampNanos() > switchProtocolAfterNanos) {
            session.getConnection()
                    .switchToUdp();
            return false;
        }
        long lastRequestTimestampNanos = Math.max(session.getLastHeartbeatRequestTimestampNanos(),
                session.getLastRequestTimestampNanos());
        long localCloseIdleSessionAfterNanos = closeIdleSessionAfterNanos;
        // 2. Check whether to close the session
        if (localCloseIdleSessionAfterNanos > 0
                && nowNanos - lastRequestTimestampNanos > localCloseIdleSessionAfterNanos) {
            sessionService
                    .closeLocalSession(session.getUserId(),
                            session.getDeviceType(),
                            HEARTBEAT_TIMEOUT)
                    .subscribe(null,
                            t -> LOGGER.error(
                                    "Caught an error while closing the local user session ({}) with the close reason: {}",
                                    session,
                                    HEARTBEAT_TIMEOUT,
                                    t));
            return false;
        }

        // 3. Check whether to update session data in Redis
        // Limit the frequency of sending heartbeat requests to Redis
        long lastHeartbeatUpdateTimestampNanos = session.getLastHeartbeatUpdateTimestampNanos();
        long localMinHeartbeatIntervalNanos = minHeartbeatIntervalNanos;
        if (localMinHeartbeatIntervalNanos > 0
                && nowNanos - lastHeartbeatUpdateTimestampNanos < localMinHeartbeatIntervalNanos) {
            return false;
        }
        // Only update session data in Redis if the client has
        // sent any request to the local node after the last heartbeat update request
        if (lastRequestTimestampNanos <= lastHeartbeatUpdateTimestampNanos) {
            return false;
        }
        session.setLastHeartbeatUpdateTimestampNanos(nowNanos);
        return true;
    }
@return If true, the data in Redis should be updated.
turms-gateway/src/main/java/im/turms/gateway/domain/session/manager/HeartbeatManager.java