A surpresa (nenhum evento de expiração visto quando o tempo de vida de uma chave chega a zero) não está vinculado ao Python, mas sim ao modo como o Redis está expirando as chaves.
Documento do Redis sobre o tempo de eventos expirados
Cronograma de eventos expirados
As chaves com um tempo de vida associado são expiradas pelo Redis de duas maneiras:
- Quando a chave é acessada por um comando e está expirada.
- Através de um sistema em segundo plano que procura chaves expiradas em segundo plano, de forma incremental, para poder também coletar chaves que nunca são acessadas.
Os eventos expirados são gerados quando uma chave é acessada e é encontrada expirada por um dos sistemas acima, como resultado, não há garantias de que o servidor Redis será capaz de gerar o evento expirado no momento em que a chave viverá atinge o valor de zero.
Se nenhum comando tiver como alvo a chave constantemente e houver muitas chaves com um TTL associado, pode haver um atraso significativo entre o tempo em que o tempo de vida da chave cai para zero e o momento em que o evento expirado é gerado.
Basicamente, os eventos expirados são gerados quando o servidor Redis exclui a chave e não quando o tempo de vida teoricamente atinge o valor de zero.
Pequeno teste no console
quando o Redis estiver em execução (
$ sudo service redis-server start
) Iniciei um console e assinei:
$ redis-cli
PSUBSCRIBE "__key*__:*"
Então, em outro console:
$ redis-cli
> config set notify-keyspace-events AKE
o que deve se inscrever em todos os tipos de eventos
Então continuei com experimentos neste segundo console:
> set aaa aaa
> del aaa
> set aaa ex 5
> get aaa
Todas as atividades foram vistas no console inscrito. Apenas a expiração da chave atrasou alguns segundos, às vezes chegou bem na hora.
Observe também que existem diferenças sutis nas mensagens, uma mensagem
[email protected]__:expire
outro [email protected]__:expired
. Exemplo de ouvinte spy.py
import redis
import time
r = redis.StrictRedis()
pubsub = r.pubsub()
pubsub.psubscribe("*")
for msg in pubsub.listen():
print time.time(), msg
Este código registra todos os canais existentes no redis padrão e imprime o que for publicado.
Executá-lo:
$ python spy.py
e em outro console tente definir uma chave com validade. Você verá todos os eventos.
Para a seguinte entrada redis-cli.
$ redis-cli
127.0.0.1:6379> set a aha
OK
127.0.0.1:6379> set b bebe ex 3
OK
127.0.0.1:6379> set b bebe ex 3
OK
obtemos saída do espião:
1401548400.27 {'pattern': None, 'type': 'psubscribe', 'channel': '*', 'data': 1L}
1401548428.36 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:a', 'data': 'set'}
1401548428.36 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:set', 'data': 'a'}
1401548436.8 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:b', 'data': 'set'}
1401548436.8 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:set', 'data': 'b'}
1401548436.8 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:b', 'data': 'expire'}
1401548436.8 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:expire', 'data': 'b'}
1401548439.82 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:b', 'data': 'expired'}
1401548439.82 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:expired', 'data': 'b'}
1401548484.46 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:b', 'data': 'set'}
1401548484.46 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:set', 'data': 'b'}
1401548484.46 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:b', 'data': 'expire'}
1401548484.46 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:expire', 'data': 'b'}
1401548487.51 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:b', 'data': 'expired'}
1401548487.51 {'pattern': '*', 'type': 'pmessage', 'channel': '[email protected]__:expired', 'data': 'b'}