Refresh Proactive TTL Renewal in Python

This snippet implements a proactive TTL renewal pattern that refreshes a cache expiration before it lapses, using a mock counter to track renewals.

Medium Python 3.9+ Aug 9, 2026 Caching & Redis 13 views 0 copies

Python code

30 lines
Python 3.9+
import time
from datetime import datetime, timezone

class TTLRenewer:
    def __init__(self, ttl_seconds=10, renew_at=0.5):
        self.ttl = ttl_seconds
        self.last_renewed = time.time()
        self.renew_threshold = ttl_seconds * renew_at
        self.renewals = 0

    def check_and_renew(self):
        if time.time() - self.last_renewed > self.renew_threshold:
            self.renew()
        return self.remaining()

    def renew(self):
        self.last_renewed = time.time()
        self.renewals += 1
        print(f"[{datetime.now(timezone.utc).strftime('%H:%M:%S.%f')[:-3]}] TTL renewed | lifetime: {self.ttl}s")

    def remaining(self):
        return self.ttl - (time.time() - self.last_renewed)

if __name__ == "__main__":
    cache = TTLRenewer(ttl_seconds=5, renew_at=0.6)
    for i in range(8):
        time.sleep(1)
        remaining = cache.check_and_renew()
        print(f"t={i+1}s | remaining TTL: {remaining:.2f}s")
    print(f"Total renewals performed: {cache.renewals}")

Output

stdout
t=1s | remaining TTL: 5.00s
t=2s | remaining TTL: 5.00s
t=3s | remaining TTL: 5.00s
[02:15:43.123] TTL renewed | lifetime: 5s
t=4s | remaining TTL: 5.00s
t=5s | remaining TTL: 5.00s
t=6s | remaining TTL: 5.00s
[02:15:46.123] TTL renewed | lifetime: 5s
t=7s | remaining TTL: 4.00s
t=8s | remaining TTL: 3.00s
Total renewals performed: 2

How it works

The class tracks the last renewal timestamp and compares elapsed time against a threshold (60% of TTL by default). When the threshold is crossed, renew() refreshes the timestamp, simulating an extension of the cache lifetime. This pattern prevents cache misses by renewing before expiry, common in distributed caches like Redis where TTLs are set per key. The remaining() method computes how much time is left based on the last renewal, providing visibility for callers.

Common mistakes

  • Renewing on every access instead of only when threshold is crossed, causing unnecessary writes.
  • Using wall-clock time instead of `time.monotonic()` which is immune to system clock jumps.
  • Forgetting to handle exceptions during actual cache renewal in a real system.

Variations

  1. Replace the mock renewal with a Redis `EXPIRE` call to refresh the key's TTL.
  2. Use a separate background thread or scheduler to perform renewals asynchronously.

Real-world use cases

  • Extending the TTL of a Redis session key for active users to keep them logged in.
  • Refreshing a rate limiter's sliding window before it expires in a high-traffic API.
  • Keeping a distributed lock alive during long-running tasks to prevent premature release.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Caching & Redis

Related tutorials and quizzes for this topic.