Niespodzianka (brak zdarzeń wygaśnięcia, gdy czas życia klucza osiągnie zero) nie jest związana z Pythonem, ale raczej ze sposobem, w jaki Redis wygasa klucze.
Dokument Redis dotyczący terminów wygasłych wydarzeń
Czas wygasłych wydarzeń
Klucze z powiązanym czasem życia są wygasane przez Redis na dwa sposoby:
- Kiedy klucz jest dostępny za pomocą polecenia i okazuje się, że wygasł.
- Za pośrednictwem systemu działającego w tle, który stopniowo wyszukuje wygasłe klucze w tle, aby móc również zbierać klucze, do których nigdy nie uzyskuje się dostępu.
Zdarzenia, które wygasły są generowane, gdy klucz jest uzyskiwany i okazuje się, że wygasł w jednym z powyższych systemów, w wyniku czego nie ma gwarancji, że serwer Redis będzie w stanie wygenerować zdarzenie, które wygasło w momencie, gdy klucz będzie aktywny osiągnie wartość zero.
Jeśli żadne polecenie nie jest stale kierowane do klucza, a istnieje wiele kluczy z powiązanym TTL, może wystąpić znaczne opóźnienie między momentem, w którym czas życia klucza spadnie do zera, a momentem wygenerowania zdarzenia, które wygasło.
Zasadniczo zdarzenia wygasłe są generowane, gdy serwer Redis usuwa klucz a nie wtedy, gdy czas życia teoretycznie osiągnie wartość zero.
Mały test na konsoli
gdy Redis działa ($ sudo service redis-server start
)
Uruchomiłem jedną konsolę i zasubskrybowałem:
$ redis-cli
PSUBSCRIBE "__key*__:*"
Następnie w innej konsoli:
$ redis-cli
> config set notify-keyspace-events AKE
co subskrybuje wszelkiego rodzaju wydarzenia
Następnie kontynuowałem eksperymenty w tej drugiej konsoli:
> set aaa aaa
> del aaa
> set aaa ex 5
> get aaa
Wszystkie działania były widoczne w subskrybowanej konsoli. Tylko wygaśnięcie ważności klucza było czasami opóźnione o kilka sekund, czasami nadchodziło w samą porę.
Zauważ też, że istnieją subtelne różnice w wiadomościach, jedna wiadomość [email protected]__:expire
inny [email protected]__:expired
.
Przykładowy odbiornik spy.py
import redis
import time
r = redis.StrictRedis()
pubsub = r.pubsub()
pubsub.psubscribe("*")
for msg in pubsub.listen():
print time.time(), msg
Ten kod rejestruje się na wszystkich istniejących kanałach w domyślnym redis i drukuje wszystko, co zostanie opublikowane.
Uruchom to:
$ python spy.py
a w innej konsoli spróbuj ustawić klucz z wygaśnięciem. Zobaczysz wszystkie wydarzenia.
Do śledzenia danych wejściowych 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
otrzymujemy dane szpiegowskie:
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'}