Run memory retention, growth control and state schema migration¶
Draft outline: not validated
Drafted with AI from official sources on 16 Oct 2026. Do not use on a live system until it is written, dry-run by someone other than the author and signed off (planned 2026-12-03). Author: James · dry-run: Sivaraj · sign-off: Prasanna. Work items: AGT-04-T13, AGT-04-T14, AGT-04-T15, AGT-04-T16.
1. Summary¶
On a weekly schedule, when storage alerts fire, or before deploying a change to the state schema.
Risk: Medium (purging active threads or breaking resume after a schema change). Typical duration: 1-2 hours per run; a day for a schema migration.
2. When to use and when not to¶
Use it when: On a weekly schedule, when storage alerts fire, or before deploying a change to the state schema.
Do not use it when: to be written by the author.
3. What you must know first¶
- Checkpoint tables grow with every super-step
- delete_thread removes all checkpoints for a thread
- Summarising long threads cuts tokens and storage
- State schema changes must still load old checkpoints
- Point-in-time restore is the fallback for a bad purge
4. Prerequisites and access¶
- Thread registry with last_active and legal_hold columns
- Database backup confirmed
- Change window for schema migrations
- Sandbox copy of data
5. Steps¶
Outline of the steps; the author adds the commands and a check after each one.
- Check storage growth and top threads by checkpoint count
- Run the purge in dry-run mode and review counts
- Run the purge in batches outside peak hours
- Summarise long active threads where the template supports it
- For schema changes, add new fields as optional with defaults
- Load sample old checkpoints with the new code in sandbox
- Deploy and watch resume errors
- Rollback: restore from point-in-time backup if active threads were purged
Draft snippet: Purge stale threads in batches using the registry
import psycopg
from langgraph.checkpoint.postgres import PostgresSaver
DB_URI = "${PG_CONN_STRING}"
RETENTION_DAYS = 30
BATCH = 500
FIND_STALE = (
"SELECT thread_id FROM agent_thread_registry "
"WHERE last_active < now() - make_interval(days => %s) AND legal_hold = false "
"ORDER BY last_active LIMIT %s"
)
with psycopg.connect(DB_URI) as conn, PostgresSaver.from_conn_string(DB_URI) as saver:
stale = [row[0] for row in conn.execute(FIND_STALE, (RETENTION_DAYS, BATCH)).fetchall()]
for thread_id in stale:
saver.delete_thread(thread_id)
conn.execute("UPDATE agent_thread_registry SET purged_at = now() WHERE thread_id = %s", (thread_id,))
conn.commit()
print(f"purged {len(stale)} threads older than {RETENTION_DAYS} days")
Snippets to add:
snippets/ops/purge_stale_threads.py: Batch purge of stale threads (python)snippets/infra/jobs/memory-retention.yaml: Scheduled job definition (yaml)
6. Monitoring and alerts¶
| Signal | Alert when | Action |
|---|---|---|
| Checkpoint table size growth per week | Above 20 percent | Run this runbook and review retention |
| Retention job failures | Any | Fix and rerun within 24 hours |
| Resume errors after a deploy | Any | Pause deploys and run PB-AGT-05-04 |
7. Rollback¶
To be written by the author: how to undo each risky step.
8. Known issues and fixes¶
| Symptom | Likely cause | Fix |
|---|---|---|
| Database keeps growing after purge | Space not reclaimed | Check autovacuum and table bloat with the DBA |
| Active thread purged | last_active not updated on resume | Update the registry on every run |
| KeyError on resume after deploy | New required state field | Make new fields optional with defaults |
9. AWS and open-source equivalents¶
AgentCore Memory manages expiry for short-term events; check current settings in its docs. RDS PostgreSQL uses the same purge approach.
10. Validation record¶
Pending. Planned dry-run scenario: A second engineer runs the purge on a sandbox copy with active, stale and legal-hold threads, and passes when only stale threads without hold are removed and a schema change resumes old threads.