public Mono<Void> blockClients(Set<T> clientIds, long blockDurationMillis) {
        if (CollectionUtils.isEmpty(clientIds) || blockDurationMillis <= 0) {
            return Mono.empty();
        }
        return syncTaskScheduler.schedule(Mono.defer(() -> {
            long now = System.currentTimeMillis();
            long blockEndTimeMillis =
                    MathUtil.add(now, blockDurationMillis, MAX_BLOCK_END_TIME_MILLIS);
            int size = clientIds.size();
            ByteBuf[] args = new ByteBuf[size + 2];
            args[0] = getBlocklistKey();
            try {
                args[1] = encodeBlockEndTimeMillis(blockEndTimeMillis);
            } catch (Exception e) {
                ReferenceCountUtil.safeEnsureReleased(args[0]);
                throw e;
            }
            int i = 2;
            try {
                for (T clientId : clientIds) {
                    BlockedClient<T> blockedClient =
                            new BlockedClient<>(clientId, blockEndTimeMillis);
                    blockedClientIdToBlockEndTimeMillis.put(clientId, blockEndTimeMillis);
                    blockedClientSkipList.add(blockedClient);
                    notifyOnTargetBlockedListener(clientId);
                    args[i++] = encodeId(clientId);
                }
                Mono<List<Object>> blockUsers = redisClient.eval(blockClientsScript, args);
                return blockUsers.flatMap(elements -> {
                    LogVersion version =
                            new LogVersion((long) elements.get(0), (int) (long) elements.get(1));
                    return checkVersionToSync(version, size);
                });
            } catch (Exception e) {
                ReferenceCountUtil.ensureReleased(args, 0, i);
                throw e;
            }
        }));
    }
Used to remove the local expired blocked clients quickly, even if there are a lot of blocked
clients so that we can run eviction more frequently.

@implNote It is acceptable to store the same IP or the user ID with different block times in
          the skip list because it is how the skip list works.
turms-server-common/src/main/java/im/turms/server/common/domain/blocklist/manager/BlocklistServiceManager.java