Redis / Valkey
SpeculaPro keeps fast-changing numbers in Redis or Valkey: how much an account received in the last hour, how many different people paid a wallet this week, how many failed sign-in attempts came from an address. Rules read these numbers in well under a millisecond, which a database could not do at thousands of transactions per second.
Valkey is an open-source fork of Redis, maintained by the Linux Foundation, and is a drop-in replacement. SpeculaPro works with both.
Valkey or Redis?
Section titled “Valkey or Redis?”| Valkey | Redis | |
|---|---|---|
| Licence | BSD (open source) | Check the current licence terms for your version and use |
| Compatibility | Same protocol and commands | |
| Recommendation | Default for self-hosting: simplest licensing | Fine if you already run it |
The local development stack uses Valkey 8.
Not the record, but treat it as important
Section titled “Not the record, but treat it as important”Redis holds mostly derived data: the feature store’s running totals, feature snapshots, recent decision answers kept for retries, the Decisions page statistics, and the rate limits on sign-in, single sign-on and SCIM. (While Redis can’t answer, each process applies those limits itself, per process; see Sign-in and MFA.) Losing it never loses evidence: every transaction, decision, hit and alert is in Postgres.
There is one exception: the decision spool. When Kafka is down, decided transactions wait in Redis until Kafka is back (see Real-time decisions below). While they wait, Redis is the only copy.
But there is no rebuild command for a running installation. The one rebuild that exists is inside a workspace move: the target region replays the workspace’s last 192 days of stored transactions and account events into its own Redis/Valkey before serving it. If Redis loses its data otherwise, the running totals start again from empty, and rules with long windows (up to 180 days) under-count until those windows refill with new transactions. So:
- Run it highly available: Sentinel or Cluster in production.
- Turn on persistence (AOF), so a restart or failover does not empty it.
- You don’t need Redis backups for disaster recovery of evidence, but an AOF file or snapshot is the only way to get the running totals back quickly after losing a server.
See Feature store: not the record, but not trivially rebuilt.
Real-time decisions
Section titled “Real-time decisions”If you use the real-time decision API, Redis/Valkey sits on the path of every payment you ask about, and it is what limits how many decisions a second you can answer within budget.
| What Redis does for decisions | Key | Kept for |
|---|---|---|
| Running totals and recent activity the rules read | f:{<workspace>:<type>:<id>}… |
The rule windows (up to 180 days) |
| The answer to each decision, so a retry gets the same answer. While a decision is still being made, the same key holds a short claim, so a duplicate request sent at the same moment is told to retry | xid:{<workspace>}:<external_id> |
SP_DECISION_IDEMPOTENCY_TTL (72 hours); a claim lasts at most 30 seconds |
| Decided transactions Kafka couldn’t take yet: the spool | spool:{decisions} |
Until Kafka takes them; normally empty |
What it costs. One decision runs a few hundred Redis commands (about 400 with the demo’s rule packs, counting the post-event monitoring of the same transaction), most of them inside scripts, so only about 15 round trips. How many each decision needs depends on your rules: each rule window reads one time bucket per hour or day it covers, so a 48-hour window reads 48 hourly buckets.
How to scale it. Every running-total key carries a hash tag, the part in {…}: the workspace and one customer, account, counterparty or device. In Cluster mode, all keys with the same tag live on the same shard, so one entity’s totals are read together, and different entities spread evenly across shards. Adding shards adds capacity close to linearly. The decision service itself keeps no state, so add decision nodes behind a load balancer as needed.
What to set:
- Sentinel or Cluster, never a single node: if Redis is down, every decision is answered by the failure policy.
maxmemory-policy noeviction. With an eviction policy such asallkeys-lru, Redis would quietly delete running totals, retry answers or spooled transactions when it fills up. Withnoeviction, writes fail instead, which SpeculaPro reports and you can alert on.- Persistence (AOF), so that a restart doesn’t empty the spool or the running totals.
SP_REDIS_POOL_SIZEon decision nodes. The decision role keeps its own connection pool of this size; a decision waiting for a free connection may run out of budget. See Configuration: Redis.- Low latency between decision nodes and Redis: place them in the same data centre or availability zone.
Choosing a mode
Section titled “Choosing a mode”SpeculaPro picks the mode from your settings:
| Mode | How to configure | Choose it when |
|---|---|---|
| Standalone | One address in SP_REDIS_ADDRS |
Development, or small installations that can tolerate a short outage |
| Sentinel | Sentinel addresses in SP_REDIS_ADDRS and SP_REDIS_SENTINEL_MASTER |
Recommended for most production installations. One primary, one or two replicas, three Sentinels that promote a replica automatically if the primary fails |
| Cluster | Several node addresses, no SP_REDIS_SENTINEL_MASTER |
High volumes of real-time decisions, or very high transaction volumes: data is spread across several primaries, and capacity grows with each one |
# StandaloneSP_REDIS_ADDRS=valkey.internal:6379
# Sentinel: list the Sentinels (port 26379), not the data nodesSP_REDIS_ADDRS=s1.internal:26379,s2.internal:26379,s3.internal:26379SP_REDIS_SENTINEL_MASTER=mymaster
# ClusterSP_REDIS_ADDRS=n1.internal:6379,n2.internal:6379,n3.internal:6379Always run three Sentinels (an odd number, on separate machines), so they can agree on a failover.
Official documentation: Valkey (including Sentinel and Cluster).
Security
Section titled “Security”- Require a password (
requirepass), or better, an ACL user for SpeculaPro (SP_REDIS_USERNAME,SP_REDIS_PASSWORD). - If your Sentinels require their own credentials, set
SP_REDIS_SENTINEL_USERNAMEandSP_REDIS_SENTINEL_PASSWORD. - Turn on TLS (
SP_REDIS_TLS_ENABLED=true) when traffic crosses machines. - Never expose Redis or Valkey to the internet.
- Treat it as holding sensitive data: the decision spool can hold transaction details (see above).
Memory
Section titled “Memory”Memory grows with the number of active customers and accounts, times the number of counters per entity. Real-time decisions add one retry answer per decision for SP_DECISION_IDEMPOTENCY_TTL (72 hours by default), so at high volumes that window matters. Set maxmemory with headroom, use noeviction, and monitor usage. Measure your own figures with load testing.