feat(backend): Aenderungsfeed per Long Polling (Schritt 4)
GET /documents/{id}/changes haelt die Anfrage offen und antwortet, sobald
sich etwas tut — kumuliertes Diff seit der bekannten Version, dazu die
Ereignisse mit ihrem Absender. Ist die Basis verdichtet oder hat der Client
noch gar nichts, kommt der Volltext statt der Operationen: ein Roundtrip und
ein Sonderzustand weniger als ein eigener Fehlerpfad.
Der Feed arbeitet auf der Historie, nicht am Dokument — ein geloeschtes
Dokument muss sein DELETED noch zustellen koennen.
Blockierend auf virtuellen Threads statt DeferredResult (D76-Nachtrag 5):
So behaelt der Endpunkt die aus der Spezifikation generierte Signatur, und
API-First bleibt fuer ihn unangetastet; ein Wartender kostet trotzdem fast
nichts. Geweckt wird nach dem Commit, nie davor, und ueber einen Stempel, den
der Aufrufer VOR dem Nachsehen liest — sonst ginge ein Signal aus der Luecke
dazwischen verloren.
122 Tests. Das Szenario "ein Wartender wird geweckt" misst die Dauer: Ohne
das bestuende es auch dann, wenn der Wartende bloss in den Timeout liefe und
danach die Aenderung vorfaende. Gegenprobe: Benachrichtigung entfernt ->
genau dieses Szenario faellt; Volltext-Rueckfall entfernt -> genau jenes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ae85503b79
commit
741b41ef11
@@ -244,6 +244,64 @@ paths:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ProblemDetail"
|
||||
|
||||
/documents/{documentId}/changes:
|
||||
parameters:
|
||||
- name: documentId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
get:
|
||||
tags: [Documents]
|
||||
operationId: getDocumentChanges
|
||||
summary: Aenderungsfeed (Long Polling)
|
||||
description: >
|
||||
Liefert alles, was seit `since` geschehen ist. Gibt es nichts, haelt
|
||||
der Server die Anfrage bis zu `wait` Sekunden offen und antwortet
|
||||
sofort, sobald eine Aenderung eintrifft; sonst 204.
|
||||
|
||||
|
||||
Der Feed arbeitet auf der **Historie**, nicht am Dokument: Ein
|
||||
geloeschtes Dokument muss sein DELETED-Ereignis noch zustellen koennen.
|
||||
404 gibt es deshalb nur bei gaenzlich unbekannter UUID.
|
||||
|
||||
|
||||
Ist `since` bereits verdichtet, kann kein exaktes Diff mehr geliefert
|
||||
werden - dann enthaelt die Antwort statt `ops` den **Volltext**, und
|
||||
`fromVersion` fehlt. Der Client ersetzt seinen Stand.
|
||||
parameters:
|
||||
- name: since
|
||||
in: query
|
||||
required: true
|
||||
description: Zuletzt gesehene Version; 0 fuer "noch nichts".
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: wait
|
||||
in: query
|
||||
required: false
|
||||
description: >
|
||||
Wartezeit in Sekunden. Serverseitig geklemmt - ein Client darf
|
||||
keine beliebig lange Verbindung binden.
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
default: 25
|
||||
responses:
|
||||
"200":
|
||||
description: Aenderungen seit `since`
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ChangeFeed"
|
||||
"204":
|
||||
description: Nichts Neues innerhalb der Wartezeit
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
|
||||
components:
|
||||
responses:
|
||||
NotFound:
|
||||
@@ -448,6 +506,54 @@ components:
|
||||
items:
|
||||
$ref: "#/components/schemas/LineOperation"
|
||||
|
||||
ChangeEvent:
|
||||
description: Was an einer Version geschehen ist und wer sie eingereicht hat.
|
||||
type: object
|
||||
required: [version, changeType]
|
||||
properties:
|
||||
version:
|
||||
type: integer
|
||||
format: int64
|
||||
changeType:
|
||||
type: string
|
||||
enum: [CREATED, UPDATED, DELETED, RESTORED, ROLLED_BACK]
|
||||
clientId:
|
||||
type: string
|
||||
description: Fehlt bei Aenderungen ohne Absender (etwa ueber PUT).
|
||||
displayName:
|
||||
type: string
|
||||
description: >
|
||||
Selbstgewaehlt und ohne Anmeldung eine Behauptung - in der
|
||||
Oberflaeche nicht wie ein Nachweis darstellen.
|
||||
|
||||
ChangeFeed:
|
||||
type: object
|
||||
required: [currentVersion, events]
|
||||
properties:
|
||||
fromVersion:
|
||||
type: integer
|
||||
format: int64
|
||||
description: >
|
||||
Basis des mitgelieferten Diffs. Fehlt, wenn stattdessen `content`
|
||||
geliefert wird.
|
||||
currentVersion:
|
||||
type: integer
|
||||
format: int64
|
||||
ops:
|
||||
type: array
|
||||
description: Kumuliertes Diff von `fromVersion` bis `currentVersion`.
|
||||
items:
|
||||
$ref: "#/components/schemas/LineOperation"
|
||||
content:
|
||||
type: string
|
||||
description: >
|
||||
Volltext statt Diff - wenn `since` bereits verdichtet ist oder der
|
||||
Client noch gar nichts hat (`since=0`).
|
||||
events:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/ChangeEvent"
|
||||
|
||||
ProblemDetail:
|
||||
type: object
|
||||
description: Fehlerformat nach RFC 9457 (Problem Details)
|
||||
|
||||
Reference in New Issue
Block a user