private void startSendingRandomRequests(
            List<TurmsClient> clients,
            long firstUserId,
            int userCount,
            int requestIntervalMillis,
            int requestCountPerInterval) {
        if (clients.isEmpty()) {
            LOGGER.info("No available client to send random requests");
            return;
        }
        LOGGER.info("Start sending random requests from clients");
        int jitter = userCount / 10;
        Range<Long> fakedNumberRange =
                Range.between(Math.max(0, firstUserId - jitter), firstUserId + userCount + jitter);
        GeneratorOptions generatorOptions = new GeneratorOptions(0.8F, 0.8F, fakedNumberRange);
        thread = TurmsThread.create(ThreadNameConst.FAKE_CLIENT_MANAGER, true, () -> {
            CyclicIterator<TurmsClient> clientIterator = new CyclicIterator<>(clients);
            Set<String> excludedRequestNames =
                    Set.of(RandomRequestFactory.CREATE_SESSION_REQUEST_FILED_NAME,
                            RandomRequestFactory.DELETE_SESSION_REQUEST_FILED_NAME);
            Thread currentThread = Thread.currentThread();
            while (!currentThread.isInterrupted()) {
                int sentRequestCount = 0;
                while (sentRequestCount < requestCountPerInterval) {
                    TurmsClient client = clientIterator.next();
                    try {
                        if (!client.isOpen()) {
                            removeCurrentClient(clientIterator, client);
                            continue;
                        }
                        TurmsRequest request =
                                RandomRequestFactory.create(excludedRequestNames, generatorOptions);
                        client.sendRequest(request)
                                .subscribe(null, t -> {
                                    LOGGER.error("Caught an error while sending the request: {}",
                                            ProtoFormatter.toLogString(request),
                                            t);
                                    if (ThrowableUtil.isDisconnectedClientError(t)) {
                                        removeCurrentClient(clientIterator, client);
                                    }
                                });
                    } catch (Exception e) {
                        LOGGER.error("Caught an error while sending a request", e);
                    }
                    sentRequestCount++;
                }
                try {
                    Thread.sleep(Math.max(1, requestIntervalMillis));
                } catch (InterruptedException e) {
                    for (TurmsClient client : clients) {
                        client.logout()
                                .subscribe(null,
                                        t -> LOGGER.error(
                                                "Caught an error while closing the session: {}",
                                                client.getSessionIdDesc(),
                                                t));
                    }
                    break;
                }
            }
            LOGGER.warn("All fake clients has been closed");
        });
        thread.start();
    }
The main reason to prepare clients in an async way is to recover from "Connection reset" to
retry to connect without blocking the server
turms-gateway/src/main/java/im/turms/gateway/infra/fake/ClientFakingManager.java