Redis from Python

The Python half of caching with Redis — connect with redis-py, store self-expiring keys, and build cooldowns and rate limits in a few lines, mirroring the Node guide.

Caching with Redis runs a Redis server on Falix and uses it from Node. This is the same story from Python: connect with the redis-py library, then lean on Redis's one superpower — keys that delete themselves — to build cooldowns, rate limits, and sessions with almost no code. The Falix setup and the golden rule (never keep your only copy of anything in a cache) are identical, so this guide focuses on the Python.

At a glance
You need A Redis server on Falix, and a Python app to connect from
Plan Any
Read first Caching with Redis — running the Redis server, and what never to cache

Get a Redis server

Redis runs as its own Falix application — create a server (or switch a spare server in Settings; switching reinstalls and wipes files, so use a fresh one) and pick Redis 7. At install it binds your server's public port and generates a password into the Redis Password variable in Settings → variables. You reach it at the server's public address and port from the Network page. Full walkthrough and the trade-offs are in Run your own database server.

⚠️ Heads up: On a free plan the Redis server stops when its session timer runs out, and every app caching to it starts throwing connection errors the moment it does. Keep Redis on a server you keep online if real traffic depends on it. See Keeping apps online.

Install redis-py

The package is called redis on PyPI. Install it from the Packages page (search redis, install, then restart so your app loads it). Keep the connection details in your .env — host and port are the Redis server's public (or internal) address, password is its Redis Password value:

REDIS_HOST=your-redis-address
REDIS_PORT=12345
REDIS_PASSWORD=the-generated-password

Connect

Read those from the environment and hand them to redis.Redis. Pass decode_responses=True so you get back plain strings instead of bytes:

import os
import redis

r = redis.Redis(
    host=os.environ["REDIS_HOST"],
    port=int(os.environ["REDIS_PORT"]),
    password=os.environ["REDIS_PASSWORD"],
    decode_responses=True,
)

print("connected:", r.ping(), flush=True)   # True

r.set("greeting", "hello")
print(r.get("greeting"), flush=True)          # "hello"

💡 Tip: flush=True makes output appear in the Console immediately — Python otherwise buffers it, so logs can look frozen on a long-running app.

Self-expiring keys: the whole point

What makes Redis a cache is expiry. Pass ex=seconds to set and the key deletes itself when the time is up — no cleanup code, ever. That one feature powers sessions, cooldowns, and rate limits.

A session token that lasts an hour and then vanishes:

r.set(f"session:{token}", user_id, ex=3600)   # gone in 3600 seconds
# later
user_id = r.get(f"session:{token}")            # None once it has expired

A command cooldown in three lines. set(..., nx=True, ex=...) sets the key only if it doesn't already exist and returns True when it did — so a True means "allowed", anything else means "still cooling down":

def check_cooldown(user_id, seconds=60):
    # True  -> allowed (key was just set)
    # False -> still on cooldown (key already existed)
    return r.set(f"cooldown:{user_id}", "1", nx=True, ex=seconds) is True

A rate limit — count requests under a key with a short expiry. incr creates the key at 1, so set the window's expiry only on that first hit:

def under_limit(user_id, limit=5, window=60):
    key = f"rate:{user_id}"
    count = r.incr(key)
    if count == 1:
        r.expire(key, window)     # start the window on the first request
    return count <= limit

That's the same three patterns as the Node guide, one-for-one — set with ex, set with nx, and incr+expire.

What to cache — and what never to

The rule doesn't change with the language: Redis is a cache, not a safe. A reinstall or application switch wipes it, and a crash can drop everything written since the last snapshot. So cache things that are temporary or that you can always recompute; keep the single copy of anything important in a durable store.

Cache it Never keep only here
Cooldowns, rate limits, session tokens Users, orders, posts
Expensive query results, API responses, a leaderboard you can rebuild Bot configuration you can't regenerate

Durable records belong in a managed database; cache in front of it, never instead of it. The full "what not to cache" reasoning lives in Caching with Redis.

Verify it works

Start the server and watch the Console. A successful boot prints connected: True from the ping(), and your get returns the value you just set. Test a cooldown by calling check_cooldown twice in a row — the first returns True, the second False until the window passes.

Troubleshooting

  • redis.exceptions.ConnectionError — wrong host/port, or the Redis server is stopped. Use the address and port from the Redis server's Network page (or its internal address), and confirm it's running; on free, its timer may have expired.
  • AuthenticationError / WRONGPASS — the password is missing or wrong. Copy the Redis Password variable exactly into REDIS_PASSWORD.
  • Values come back as b'...' bytes — you didn't pass decode_responses=True to redis.Redis(...). Add it, or decode each value yourself.
  • ModuleNotFoundError: No module named 'redis' — install redis from the Packages page and restart. See My app won't start.
  • The cache is suddenly empty — a reinstall or application switch wiped Redis, or a crash lost recent writes. Never store anything in Redis you can't rebuild.

Beyond these patterns it's standard Redis — the official documentation at redis.io covers the full command set and the redis-py client in depth.


Next steps

Was this guide helpful?