mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-17 18:25:42 +02:00
[eric] apps: the scaffold ships a durable store and the skill forbids memory-only state, since the runtime dies on a timer
This commit is contained in:
@@ -274,6 +274,22 @@ and flips `BACKEND_PORT` in both `.env` and `.env.example`. Then run
|
||||
- Install your own venv or `pip install` manually.
|
||||
- Edit `backend/run.sh` or the SubApp framework.
|
||||
|
||||
**Persist anything the user comes back to. Your process is disposable.**
|
||||
OpenSwarm freezes this app's process when its card closes and fully kills
|
||||
it after ~15 minutes idle, on quit, and on crash. A module-level list or
|
||||
dict is therefore data loss on a timer. The scaffold ships a durable
|
||||
store; use it (or your own files under `backend/data/`):
|
||||
|
||||
```python
|
||||
from backend.apps.store.store import load_store, save_store
|
||||
|
||||
data = load_store() # {} on first run, never raises
|
||||
data["items"] = [*data.get("items", []), new_item]
|
||||
save_store(data) # atomic write; a kill mid-write keeps the old data
|
||||
```
|
||||
|
||||
Holding state only in memory is a bug, not a style choice.
|
||||
|
||||
Adding a new endpoint is just adding a new SubApp:
|
||||
|
||||
```python
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
"""Disk-backed app state. Use this instead of module-level variables for anything worth keeping.
|
||||
|
||||
The app's process is DISPOSABLE: OpenSwarm freezes it when its card closes, kills it after ~15
|
||||
minutes idle, on quit, and on crash. A module-level list or dict therefore silently loses the
|
||||
user's data on a schedule you don't control. This store survives all of that: one JSON file under
|
||||
backend/data/, written atomically so a kill mid-write can never corrupt it.
|
||||
|
||||
from backend.apps.store.store import load_store, save_store
|
||||
|
||||
items = load_store().get("items", [])
|
||||
items.append(new_item)
|
||||
save_store({**load_store(), "items": items})
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
from typing import Any, Dict
|
||||
|
||||
from typeguard import typechecked
|
||||
|
||||
P_BACKEND_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
DATA_DIR = os.path.join(P_BACKEND_DIR, "data")
|
||||
STORE_PATH = os.path.join(DATA_DIR, "store.json")
|
||||
|
||||
|
||||
@typechecked
|
||||
def load_store() -> Dict[str, Any]:
|
||||
"""The whole store as a dict; empty on first run or an unreadable file, never an exception."""
|
||||
try:
|
||||
with open(STORE_PATH, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
return data if isinstance(data, dict) else {}
|
||||
except (FileNotFoundError, json.JSONDecodeError, OSError):
|
||||
return {}
|
||||
|
||||
|
||||
@typechecked
|
||||
def save_store(data: Dict[str, Any]) -> None:
|
||||
"""Replace the store atomically: temp file then rename, so a kill mid-write leaves the old data."""
|
||||
os.makedirs(DATA_DIR, exist_ok=True)
|
||||
fd, tmp = tempfile.mkstemp(dir=DATA_DIR, suffix=".tmp")
|
||||
try:
|
||||
with os.fdopen(fd, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=1)
|
||||
os.replace(tmp, STORE_PATH)
|
||||
except OSError:
|
||||
try:
|
||||
os.unlink(tmp)
|
||||
except OSError:
|
||||
pass
|
||||
raise
|
||||
Reference in New Issue
Block a user