docs: Firehose, Follow-Lexicon und Phase 10
architecture.md zeigt den subscribeRepos-Pfad im Diagramm (er stand zuerst irrtümlich am Pfeil zum externen Relay) und erklärt, warum es Push *und* Firehose gibt: der eine ist schnell, der andere verlässlich. Dazu, wo die Spec-Treue endet — die Frame-Hülle ist konform, die Blöcke darin nicht. deployment.md bekommt einen Firehose-Abschnitt: Transaktionsgarantie, warum die seq lückenfrei ist und was der globale Advisory-Lock an Durchsatz kostet, Cursor-Semantik, WebSocket-Upgrade im Proxy, und die fehlende Retention für firehose_events. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HC9HLrUU1LNwkzp8nkDLX
This commit is contained in:
co-authored by
Claude Opus 5
parent
6fbea4fe6f
commit
b7ce114677
+38
-5
@@ -287,7 +287,7 @@ Hinweise:
|
||||
* Es gibt **keinen** Signal-Handler für graceful Shutdown. `systemctl stop`
|
||||
beendet den Prozess hart; bei der AppView bedeutet das, dass der letzte
|
||||
Cursor-Flush nur passiert, wenn der Kanal regulär geschlossen wird —
|
||||
praktisch also mit bis zu 100 Events Verlust (siehe Abschnitt 9). Das ist
|
||||
praktisch also mit bis zu 100 Events Verlust (siehe Abschnitt 10). Das ist
|
||||
unkritisch, weil der Cursor beim Resume ohnehin leicht in die Vergangenheit
|
||||
zeigt und Events idempotent verarbeitet werden.
|
||||
* Eine Abhängigkeit `After=` auf Postgres/MinIO ist nur nötig, wenn diese auf
|
||||
@@ -344,7 +344,33 @@ Instanz hinter VPN und für die fail-open-Integrationstests. Die AppView warnt
|
||||
beim Start in Großbuchstaben. Öffentlich erreichbar heißt das: jeder kann die
|
||||
Notifications jeder DID lesen und als gelesen markieren.
|
||||
|
||||
## 7. Reverse-Proxy
|
||||
## 7. Firehose
|
||||
|
||||
Die PDS liefert `com.atproto.sync.subscribeRepos` als WebSocket aus, die
|
||||
AppView konsumiert ihn. Betrieblich wichtig:
|
||||
|
||||
* **Das Event liegt in derselben Transaktion wie der Commit.** Es kann keinen
|
||||
Commit ohne Event geben und umgekehrt.
|
||||
* **Die `seq` ist lückenfrei.** Ein globaler `pg_advisory_xact_lock` sorgt
|
||||
dafür, dass Commit-Reihenfolge und `seq`-Reihenfolge übereinstimmen — sonst
|
||||
könnte ein Consumer eine Nummer überspringen, die erst danach sichtbar wird,
|
||||
und sie nie nachholen. Preis: das Ende jeder schreibenden Transaktion ist
|
||||
über alle Accounts hinweg serialisiert.
|
||||
* **Cursor:** `?cursor=<seq>` liefert alles mit `seq > cursor` aus der
|
||||
Datenbank nach und geht dann nahtlos live weiter. Ohne Cursor nur live. Ein
|
||||
Cursor aus der Zukunft ist ein Fehler-Frame, ein zu alter ein
|
||||
`#info`/`OutdatedCursor`.
|
||||
* **`firehose_events` wächst unbegrenzt.** Es gibt keine Retention. Beschneiden
|
||||
ist sicher, weil ein zu alter Cursor sauber behandelt wird — wer die Tabelle
|
||||
aufräumt, sollte aber wissen, wie weit die eigenen Consumer zurückhängen
|
||||
dürfen (`pds_firehose_seq` in `/healthz` der AppView gegen `MAX(seq)`).
|
||||
* **Reverse-Proxy:** die Route braucht ein WebSocket-Upgrade (`Upgrade`/
|
||||
`Connection`-Header durchreichen) und einen Read-Timeout, der längere
|
||||
Ruhephasen überlebt.
|
||||
* `PDS_FIREHOSE_ENABLED=false` schaltet den Consumer in der AppView ab; lokale
|
||||
Commits hängen dann wieder allein am Best-Effort-Push.
|
||||
|
||||
## 8. Reverse-Proxy
|
||||
|
||||
### PDS
|
||||
|
||||
@@ -462,7 +488,7 @@ HTTP-Aufrufe an PDS/AppView laufen über den Rust-IPC-Layer
|
||||
(`src-tauri/src/pds_client.rs`, `appview_client.rs`), nicht aus dem Webview —
|
||||
die CSP muss also für neue Backend-URLs nicht angefasst werden.
|
||||
|
||||
## 8. Health-Checks und Logs
|
||||
## 9. Health-Checks und Logs
|
||||
|
||||
### PDS
|
||||
|
||||
@@ -526,7 +552,7 @@ Log-Zeilen, auf die es sich lohnt zu achten:
|
||||
| `s3 ping failed at startup` | MinIO beim PDS-Start nicht erreichbar |
|
||||
| `plc submit failed (dev ok)` | PLC-Directory nicht erreichbar; die DID bleibt lokal gültig, ist aber global nicht registriert |
|
||||
|
||||
## 9. Neustart-Verhalten
|
||||
## 10. Neustart-Verhalten
|
||||
|
||||
**PDS.** Zustandslos bis auf Postgres und MinIO. Der In-Memory-Blockstore
|
||||
(`MemoryBlockstore` in `state.rs`) wird beim Start neu aufgebaut; persistent
|
||||
@@ -569,7 +595,7 @@ nach — zuerst über die lokale PDS (`PdsHandleResolver`, 2 s Timeout), dann PL
|
||||
bzw. `did:web`. Nach einem Neustart holt der erste Durchlauf das nach; der
|
||||
Zustand ist reine Anzeigekosmetik.
|
||||
|
||||
## 10. Was noch offen ist
|
||||
## 11. Was noch offen ist
|
||||
|
||||
* Kein Compose-Service für `pds-server` / `appview` — das Compose-File deckt nur
|
||||
Postgres und MinIO ab. Es gibt kein Dockerfile im Repo.
|
||||
@@ -581,3 +607,10 @@ Zustand ist reine Anzeigekosmetik.
|
||||
einsetzt. Signatur, Ablauf, `scope` und `sub` werden geprüft.
|
||||
* Notifications werden nie gelöscht; ein Unlike/Unfollow lässt die Zeile stehen.
|
||||
* Kein Backfill-Werkzeug für Jetstream-Lücken.
|
||||
* **Keine Retention für `firehose_events`.** Die Tabelle wächst mit jedem
|
||||
Commit und wird nie beschnitten. Pruning ist sicher — ein Consumer mit zu
|
||||
altem Cursor bekommt `#info`/`OutdatedCursor` und läuft ab der ältesten
|
||||
überlebenden Zeile weiter — aber es gibt weder Job noch Policy dafür.
|
||||
* Der globale Advisory-Lock, der die `seq`-Vergabe ordnet, serialisiert das
|
||||
Ende jeder schreibenden Transaktion über alle Accounts hinweg. Das
|
||||
begrenzt den Schreibdurchsatz auf ein COMMIT nach dem anderen.
|
||||
|
||||
Reference in New Issue
Block a user