Skip to content

feat: add RedisStore, SQLiteStore, and wire store into Mpp.create()#98

Open
brendanjryan wants to merge 5 commits intomainfrom
feat/stores
Open

feat: add RedisStore, SQLiteStore, and wire store into Mpp.create()#98
brendanjryan wants to merge 5 commits intomainfrom
feat/stores

Conversation

@brendanjryan
Copy link
Collaborator

@brendanjryan brendanjryan commented Mar 24, 2026

Summary

Adds two production-ready store backends and wires the store= parameter into Mpp.create()

Changes

New store backends (mpp.stores):

  • RedisStore — for multi-instance production deployments (Redis/Valkey). Uses SET NX EX for atomic put_if_absent. Install with pip install pympp[redis].
  • SQLiteStore — zero-infra production store using Python's built-in sqlite3 via aiosqlite. Uses INSERT OR IGNORE for atomic put_if_absent with lazy TTL expiry. Install with pip install pympp[sqlite].

Store wiring:

  • Mpp.create(store=...) and Mpp(store=...) automatically inject the store into intents that accept one (e.g., ChargeIntent). If an intent already has a store configured, it is not overwritten.

Optional dependencies in pyproject.toml:

  • pympp[redis]redis>=5.0
  • pympp[sqlite]aiosqlite>=0.20

Usage

from mpp.server import Mpp
from mpp.methods.tempo import tempo, ChargeIntent
from mpp.stores import RedisStore  # or SQLiteStore

# Redis
from redis.asyncio import from_url
store = RedisStore(await from_url("redis://localhost:6379"))

# SQLite (zero-infra alternative)
# store = await SQLiteStore.create("mpp.db")

server = Mpp.create(
    method=tempo(
        intents={"charge": ChargeIntent()},
        recipient="0x...",
    ),
    store=store,  # automatically wired into ChargeIntent
)

brendanjryan and others added 2 commits March 23, 2026 20:14
- RedisStore: production-ready store using redis-py (SET NX EX for atomic
  put_if_absent, configurable TTL and key prefix)
- SQLiteStore: zero-infra production store using aiosqlite (INSERT OR IGNORE
  for atomic put_if_absent, lazy TTL expiry)
- Mpp.create(store=...) and Mpp(store=...) automatically inject the store
  into intents that have a _store attribute (e.g. ChargeIntent)
- New optional deps: pympp[redis], pympp[sqlite]
- 27 new tests covering all store backends and wiring behavior
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b9cf62d2fd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"""
now = time.time()
await self._db.execute(
"DELETE FROM kv WHERE key = ? AND expires_at <= ?", (key, now)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Purge expired SQLite keys globally before inserts

put_if_absent only removes expired rows for the current key, but charge replay keys are transaction hashes and are almost always unique, so old rows are never revisited and never deleted. In production this makes TTL ineffective for storage reclamation, causing unbounded kv growth over time and eventual write/latency issues on long-lived servers. Expiry cleanup needs to target all expired rows (or run an equivalent global/batched vacuum path), not just the incoming key.

Useful? React with 👍 / 👎.

- Add redis service to docker-compose.yml
- 10 integration tests: CRUD, TTL verification, atomicity of
  put_if_absent under concurrent access, key prefix isolation
- Skipped automatically when REDIS_URL is not set
- Run with: docker compose up -d redis && REDIS_URL=redis://localhost:6379 uv run pytest -m redis -v
@brendanjryan brendanjryan requested a review from Slokh March 24, 2026 03:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant