perf(live): Debounce 600 ms, Sync-Versionen nur noch 5 Minuten (D79)
Gemeldet: ~3 s Verzoegerung zwischen zwei Browsern. Zerlegt statt geraten - von 1,73 s gemessenem Weg A->B entfallen 1,67 s auf die Wartezeit vor dem Senden. Alles andere sind zusammen ~70 ms. Zwei Verdaechtige sind freigesprochen: Der Server weckt den wartenden Feed 39 ms nach dem PATCH (isoliert per curl, ohne Browser), und der Apache der produktiven Instanz haelt den Long-Poll die vollen 25 s durch und schliesst sauber mit 204 - kein Fenster ohne offenen Feed, kein 5-Sekunden-Fehlerpfad. Produktiv kommen ~130 ms Rundlauf je Anfrage dazu. Der Debounce bleibt ein Debounce (kein Takt): Wer durchtippt, erzeugt weiterhin keine Version. Der Grund fuer die 1,5 s stammte aus der Rate-Limit-Disziplin des Etherpad-Konzepts - und Etherpad ist ausgebaut (D78). Die Aufbewahrung zahlt die haeufigeren Pushes: Jede Version speichert den ganzen Text, und die Frist entscheidet einzig, ob ein zurueckgefallener Client ein Diff oder den Volltext bekommt. Nutzersichtbar sind die Meilensteine, und die werden nie verdichtet; zurueckfallen kann nur ein ruhender Feed (Hintergrund-Tab). Zusammen sinkt die Spitze je aktiv getipptem Dokument von 115 MB auf 24 MB (49-kB-Plan, Dauertippen). Dabei gefunden: Eine Schreibpause laenger als die Frist war mit einer Stunde der Ausnahmefall und ist mit fuenf Minuten der Normalfall. Dass die letzte Sync-Version davor nicht verlorengeht, haengt allein daran, dass recordHistory() zuerst befoerdert und danach verdichtet - sonst loeschte die Verdichtung genau den Stand, den die Befoerderung gleich zum Meilenstein gemacht haette. Die Reihenfolge hat jetzt eine Zusicherung; vertauscht faellt genau der danach benannte Test. Werkzeuggrenze notiert: Der Automatisierungs-Browser zeigt seine Flaeche nicht an, Chrome drosselt Timer verborgener Seiten auf 1 Hz (gemessen: ein blanker setTimeout(600) feuert nach 999-1053 ms). Ein Sub-Sekunden-Debounce ist dort grundsaetzlich nicht messbar. 501 Frontend-Tests, 139 Backend-Tests.
This commit is contained in:
@@ -12,6 +12,7 @@ import io.mockk.mockk
|
||||
import io.mockk.CapturingSlot
|
||||
import io.mockk.slot
|
||||
import io.mockk.verify
|
||||
import io.mockk.verifyOrder
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.time.Clock
|
||||
import java.time.Duration
|
||||
@@ -215,6 +216,37 @@ class DocumentServiceTest {
|
||||
verify(exactly = 0) { historyRepository.promoteToMilestone(any(), any()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Eine Schreibpause, die **länger ist als die Aufbewahrungsfrist**, war mit
|
||||
* einer Stunde Frist der Ausnahmefall und ist mit fünf Minuten der
|
||||
* Normalfall (D79). Dass die letzte Sync-Version davor trotzdem nicht
|
||||
* verlorengeht, hängt an einer einzigen Sache: `recordHistory` **befördert
|
||||
* zuerst und verdichtet danach**. In der anderen Reihenfolge löschte die
|
||||
* Verdichtung genau den Stand, den die Beförderung gleich zum Meilenstein
|
||||
* gemacht hätte — ein nutzersichtbarer Stand wäre still weg.
|
||||
*/
|
||||
@Test
|
||||
fun `nach einer Pause laenger als die Frist wird zuerst befoerdert, dann verdichtet`() {
|
||||
val kurz = LiveEditingProperties(
|
||||
milestonePause = Duration.ofSeconds(30),
|
||||
syncRetention = Duration.ofMinutes(5),
|
||||
)
|
||||
val dienst = DocumentService(repository, historyRepository, clock, kurz, notifier)
|
||||
val doc = sampleDocument(version = 5)
|
||||
every { repository.findById(doc.id) } returns doc
|
||||
every { repository.save(any()) } answers { firstArg() }
|
||||
every { historyRepository.findLatest(doc.id) } returns
|
||||
historyEntry(doc.id, 5, ChangeType.UPDATED, milestone = false)
|
||||
|
||||
clock.moment = clock.moment.plusSeconds(600) // zehn Minuten Pause
|
||||
dienst.update(doc.id, "T", "C", milestone = false)
|
||||
|
||||
verifyOrder {
|
||||
historyRepository.promoteToMilestone(doc.id, 5)
|
||||
historyRepository.compact(doc.id, OffsetDateTime.now(clock).minusMinutes(5))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `nach jeder Aenderung wird jenseits der Aufbewahrungsfrist verdichtet`() {
|
||||
val doc = sampleDocument(version = 1)
|
||||
|
||||
Reference in New Issue
Block a user