Feature Specification: Resource redis
Created: 2026-10-07
Status: Implemented
Input: Reconstructed from the code of core/resources/redis/ and the setup wiring at 093e68b6f, pull requests #1184 and #1206, and issue #527.
User Scenarios & Testing (mandatory)
The redis resource connects an application to its own namespace on the valkey node of its group. It wraps the redis contract. The external provider fulfills the contract with a remote valkey instance per namespace. The shared resource rules are in the resource family spec.
User Story 1 - Connect an application to its own valkey namespace (Priority: P1)
A component needs a Redis-compatible cache. It requests a namespace under its consumer name. The policy prefixes the namespace with the group and routes the request to the external provider. The component gets a host, a port and a password file. Each namespace runs in its own valkey process with its own port and password, so two tenants do not share data.
Why this priority: the Fediverse applications keep their queues and caches in Redis.
Independent Test: a contract test with the reference valkey provider and isolated namespaces, and a VM test of the valkey service.
Acceptance Scenarios:
- Given a routed request in a group with a prefix, When the deployment is evaluated, Then the component gets the host, the port of the prefixed namespace, and a password file of that namespace.
- Given the password file, When the OpenBao agent renders it, Then its content is the static credential of the namespace. In a tenant deployment, the credential is that of the namespace of that deployment.
- Given a request that no provider is routed for, When the deployment is evaluated, Then the resource emits nothing for it, and the component keeps its local Redis.
User Story 2 - Derive the port of a namespace without a registry (Priority: P1)
The consumer and the valkey node must agree on the port of a namespace without a shared table. Both sides derive the port from a hash of the namespace name, in a fixed range.
Why this priority: a different port on the two sides breaks every connection.
Independent Test: a unit test of the port derivation with fixed vectors, and a check that the namespaces of all operator applications get distinct ports.
Acceptance Scenarios:
- Given a namespace, When the port is derived twice, Then both results are equal and in the fixed range.
- Given the namespaces of all operator applications, bare or prefixed, When the ports are derived, Then no two are equal.
User Story 3 - Hold a unit until valkey answers (Priority: P2)
A unit must not start before the valkey instance accepts connections. The request names such units. A Laravel migration needs this, because a run before the cache answers fails.
Why this priority: a migration that runs against an absent cache fails, and the unit must start again.
Independent Test: a unit test of which units have the gate, and that the probe reaches the address that the client of the application uses.
Acceptance Scenarios:
- Given a gated unit, When it starts, Then it first probes the instance at the address, the transport and the CA of the contract result.
- Given the instance answers the probe, or refuses it only for a missing or wrong password, over verified TLS or plain TCP as the result says, When the probe runs, Then the unit starts.
- Given no answer within a bounded number of attempts, each with a short timeout, When the probe ends, Then the unit does not start.
Edge Cases
- The group has no
valkeynode: the evaluation fails with that reason when a routed request reads the host. - In TLS mode without a CA from the result, the probe uses the CA bundle of the system environment, when it is set.
- TLS is off in the policy: the
valkeynode serves plain text, and each consumer gets a plain connection without a CA.
Requirements (mandatory)
Functional Requirements
- FR-001: The request MUST accept the namespace, the consumer name and the gated units. The request MUST contain only data, so that it can be serialized to JSON.
- FR-002: The policy MUST accept the host, the group prefix (empty by default), the location of the password files, the TLS setting with its CA, and the routing. It MUST expose whether the request crosses nodes, read-only.
- FR-003: The deployment MUST default the TLS setting to whether its PKI plan holds the
valkeyhost. The TLS gate of thevalkeynode, the OpenBaovalkeyengine,redis-commanderand every consumer MUST read this one value. - FR-004: The resource MUST prefix the namespace with the group prefix when the prefix is not empty.
- FR-005: The resource MUST emit consumer configuration only for a routed request, and MUST drop an unrouted request without an error.
- FR-006: The
externalprovider MUST fulfill a request with the host, the port, the application user, the password file of the namespace, the TLS setting, and the CA when TLS is on. - FR-007: The port of a namespace MUST be a pure function of its name, in a fixed range, the same on the consumer and on the
valkeynode. - FR-008: The ports of the operator application namespaces MUST be free of collisions, bare and prefixed.
- FR-009: The consumer MUST connect as the application user. That user has full access to its instance. The separate process per namespace gives the isolation.
- FR-010: The resource MUST NOT provision the
valkeydaemon or the OpenBao engine. These come from thevalkeyandopenbaocomponents. - FR-011: The resource MUST give each routed request to the consumer node through the
rediscontract, by the cross-node evaluation, so that the contract result on the consumer node holds the result. The gated units MUST reach the consumer node next to the contract result. A static consumer module MUST render the start gate from these two values only. The values MUST contain no store paths and no functions, so that they can be serialized to JSON.
Key Entities
- Namespace: the prefixed name that selects the
valkeyinstance, its port and its OpenBao static role. externalprovider: the provider that fulfills therediscontract with a remotevalkeyinstance.- Probe: a ping with retries, over TLS or plain TCP as the contract result says.
- Resolved request: the data that the static consumer module renders on the consumer node: the gated units and the contract result.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: the unit tests of the port derivation, the gate, the TLS agreement and the data-only requests pass.
- SC-002: the contract test with
valkeyand the VM test of thevalkeyservice pass. - SC-003: Two tenants of one application read and write separate keyspaces.
Assumptions
- The routing of the resource is in setups and wiring. The routing selects the
externalprovider when the group providesredis. - The
valkeynode runs one instance per namespace. See the valkey component. - The admin user of each instance holds a fixed password from a
generateFilesbootstrap. The engine rotates only the application user.
Known Deviations
None.