@Override
    public List<? extends Serializable> query(final TicketRegistryQueryCriteria queryCriteria) {
        val redisKeyGenerator = redisKeyGeneratorFactory.getRedisKeyGenerator(queryCriteria.getType()).orElseThrow();
        val redisTicketsKey = StringUtils.isNotBlank(queryCriteria.getId())
            ? redisKeyGenerator.forPrefixAndId(queryCriteria.getType(), digestIdentifier(queryCriteria.getId()))
            : redisKeyGenerator.forPrefixAndId(queryCriteria.getType(), "*");

        if (queryCriteria.isDecode()) {
            try (val scanResults = casRedisTemplates.getTicketsRedisTemplate().scan(redisTicketsKey, queryCriteria.getCount())) {
                return scanResults
                    .parallel()
                    .map(key -> {
                        val ticket = ticketCache.stream().parallel()
                            .map(cache -> cache.getIfPresent(redisKeyGenerator.rawKey(key)))
                            .filter(Objects::nonNull);
                        return ticket.findFirst().orElseGet(() -> {
                            val keyspace = redisKeyGenerator.getKeyspace();
                            val entryId = redisKeyGenerator.rawKey(key);
                            val redisDocument = redisKeyValueAdapter.get(entryId, keyspace, RedisTicketDocument.class);
                            return Stream.ofNullable(redisDocument)
                                .parallel()
                                .filter(Objects::nonNull)
                                .map(document -> deserializeTicket(document.json(), document.type()))
                                .filter(Objects::nonNull)
                                .findFirst()
                                .orElse(null);
                        });
                    })
                    .filter(Objects::nonNull)
                    .map(this::decodeTicket)
                    .filter(ticket -> StringUtils.isBlank(queryCriteria.getPrincipal())
                        || (ticket instanceof final AuthenticationAwareTicket aat
                        && StringUtils.equalsIgnoreCase(queryCriteria.getPrincipal(), aat.getAuthentication().getPrincipal().getId())))
                    .filter(ticket -> !ticket.isExpired())
                    .peek(ticket -> {
                        val cacheKey = redisKeyGenerator.forPrefixAndId(ticket.getPrefix(), digestIdentifier(ticket.getId()));
                        ticketCache.ifAvailable(c -> c.put(redisKeyGenerator.rawKey(cacheKey), ticket));
                    })
                    .collect(Collectors.toList());
            }
        }
        val keys = fetchKeysForTickets(redisTicketsKey);
        return (queryCriteria.getCount() > 0 ? keys.limit(queryCriteria.getCount()) : keys).collect(Collectors.toList());
    }
Key-value ticket registry implementation that stores tickets in redis.

@author Misagh Moayyed
@author Jerome Leleu
@since 5.1.0
support/cas-server-support-redis-ticket-registry/src/main/java/org/apereo/cas/ticket/registry/RedisTicketRegistry.java