Burn-After-Reading Zero-RTT Auto-Destruction
Since version v0.55.0
Spedo introduces native Burn-After-Reading Zero-RTT Auto-Destruction, enabling secure single-use or quota-bounded keys (OTPs, temporal secrets, payment tokens, claim tickets) with zero network overhead.
1. Overview & Architecture
Traditional Redis setups implement single-use secrets via Multi/Exec blocks or Lua scripts (GET followed by DEL), incurring multiple roundtrips, atomic serialization latency, or application-level race conditions.
Spedo natively integrates read counting directly into its lock-free memory entries. When a key is created with read limits, the storage engine atomically tracks accesses and cleans up the memory entry immediately upon consumption without extra client roundtrips.
+------------------+ SET key val EXPIRE_READS 1 +-------------------+
| Client (App) | -----------------------------------------> | Spedo Server |
| | | (quota: 1 read) |
+------------------+ +-------------------+
|
| 1. GET key (Returns value)
v
+------------------+ Zero-RTT Auto-Destruction +-------------------+
| Client (App) | <========================================= | Atomic Eviction |
| (Receives Secret)| | (Key Purged) |
+------------------+ +-------------------+
|
| 2. GET key (Subsequent read)
v
+------------------+
| (nil) | Key is guaranteed non-existent
+------------------+2. RESP Protocol Commands
BURN.SET / SET ... EXPIRE_READS
Sets a key with a designated read allowance and optional TTL:
BURN.SET <key> <value> <reads> [ttl_seconds]
SET <key> <value> EXPIRE_READS <count> [EX <ttl_seconds>]PEEK
Inspects the key value without decrementing its remaining read credits or resetting its TTL:
PEEK <key>READS.REMAINING
Queries the number of remaining valid reads left before automatic eviction:
READS.REMAINING <key>Returns integer count of remaining reads, or -1 if the key has infinite reads (standard key).
3. Python SDK Usage
from spedo import SpedoClient
client = SpedoClient(host="127.0.0.1", port=6380)
# Store an OTP token valid for exactly 1 read
client.burn_set("auth:otp:user_123", "948201", reads=1, ttl=300)
# Check remaining quota without consuming it
remaining = client.reads_remaining("auth:otp:user_123")
print(f"Reads left: {remaining}") # 1
# Peek at value without consuming read credit
preview = client.peek("auth:otp:user_123")
print(f"Peek preview: {preview}") # b'948201'
# Read #1 (consumes the single read quota)
token = client.get("auth:otp:user_123")
print(f"Consumed token: {token}") # b'948201'
# Read #2 (automatically burned!)
burned = client.get("auth:otp:user_123")
print(f"Subsequent read: {burned}") # None