Metadata-Version: 2.4
Name: splent_feature_redis
Version: 1.6.0
License-Expression: LGPL-3.0-or-later
Requires-Python: >=3.13
Description-Content-Type: text/markdown
License-File: COPYING
License-File: COPYING.LESSER
Dynamic: license-file

# splent_feature_redis

Redis infrastructure for SPLENT products (config archetype). It brings a
Redis 7.4 container and puts in the app's configuration how to reach it, so
other features can use Redis without knowing where it runs or what its
password is. Sessions are a separate feature, `splent_feature_session_redis`,
which requires this one.

## What it provides

In `app.config`:

| Key | Value |
| --- | --- |
| `REDIS_URL` | The server, with `REDIS_PASSWORD` in it when one is set. |
| `REDIS_SESSION_URL` | The same server on the sessions database, `REDIS_SESSION_DB`. |
| `REDIS_TASKS_URL` | The same server on the tasks database, `REDIS_TASKS_DB`. |
| `REDIS_CACHE_URL` | The same server on the cache database, `REDIS_CACHE_DB`. |
| `REDIS_SESSION_DB`, `REDIS_TASKS_DB`, `REDIS_CACHE_DB` | The database numbers. |

A feature that keeps something in Redis reads the URL for its use and hands
it to `redis.from_url`. Each use has a logical database of its own: a cache
may be flushed whenever it is in the way, queued tasks may not, and neither
may take the sessions with it.

Docker, one `redis:7.4` service named `splent_feature_redis` with its data
in the `redis_data` volume:

- `docker/docker-compose.dev.yml` publishes port 6379 on the host as
  `REDIS_HOST_PORT`, and runs without a password unless `REDIS_PASSWORD` sets
  one, like the rest of the development stack.
- `docker/docker-compose.prod.yml` publishes no port, so only the product's
  own containers reach Redis, and always runs with `requirepass`. It refuses
  to start until `REDIS_PASSWORD` is set.

## Configuration

| Env var | Default | Purpose |
| --- | --- | --- |
| `REDIS_URL` | `redis://localhost:6379` | Where the server is. The Docker `.env` sets `redis://splent_feature_redis:6379` for container-to-container access. Leave the password out of it. |
| `REDIS_PASSWORD` | empty | Password of the server. Empty in development (`docker/.env.example`); `<SET>` in production (`docker/.env.prod.example`), so `product:deploy` generates one and `docker compose up` refuses to start without it. The server and the app read this same variable. |
| `REDIS_SESSION_DB` | `0` | Logical database of the sessions. |
| `REDIS_TASKS_DB` | `1` | Logical database of background tasks and their queue. |
| `REDIS_CACHE_DB` | `2` | Logical database of caches, which may be flushed at any time. |
| `REDIS_HOST_PORT` | `6380` | Host port published in development only. Gets the product's port offset. |

Credentials written into `REDIS_URL` (`rediss://user:password@host:6380`) win
over `REDIS_PASSWORD`. That is how a product points at a Redis it does not
run, such as a managed one with a user of its own. A database in the URL is
replaced by the one each use is configured with.

The database settings are declared in `[tool.splent.config]`, so a product
changes them there. A value that is not a database number, or one that two
uses share, stops the app at start-up rather than quietly putting two uses
in one database. A number the server does not have fails at the first
connection instead, since only the server knows how many it has: the
feature's own has 16, from 0 to 15.

## Upgrading from 1.5

- A production deployment needs `REDIS_PASSWORD`. `product:deploy` asks for
  it and offers a random one; on a host without the CLI, set it in
  `deploy/.env` before `docker compose up`.
- Redis is no longer published on the host in production. Anything that
  reached it through `REDIS_HOST_PORT` has to run inside the product's
  network now.
- The data moves to the `redis_data` volume, which survives
  `docker compose down`. The first start of this version begins with it
  empty, so everyone signs in once more.
- `REDIS_WORKER_TIMEOUT` is gone. Nothing read it.

## Use it in a product

```bash
splent feature:add splent_feature_redis
```

## Tests

```bash
splent feature:test splent_feature_redis
```

The unit tests build the URLs against a bare Flask app and parse them with
redis-py, which opens no connection, so no server is needed.
