Merge pull request #36002 from overleaf/mj-save-backup-early

[web] Start saving offline backups after 10 seconds

GitOrigin-RevId: 4101598f46b6f71dc8bf10a31cbec9110216ed7a
This commit is contained in:
Mathias Jakobsen
2026-09-17 11:43:27 +00:00
committed by Copybot
parent ffeb3ef5de
commit 0c5e55a8be
2 changed files with 63 additions and 2 deletions
@@ -15,6 +15,7 @@ const PROJECT_ID = 'project-456'
const USER_ID = 'user-789'
const KEY = `doc.offline-backup.${USER_ID}.${PROJECT_ID}.${DOC_ID}`
const FLUSH_DELAY = 2000
const STALL_AFTER_MS = 10000
const SYNCED_EVENT = 'ide:offlineChangesSynced'
class FakeShareJsDoc extends EventEmitter {
@@ -27,6 +28,8 @@ class FakeShareJsDoc extends EventEmitter {
snapshot = 'server text'
inflightOp: ShareJsOperation | null = null
pendingOp: ShareJsOperation | null = null
inflightOpCreatedAt: number | null = null
pendingOpCreatedAt: number | null = null
track_changes = false
otType: OTType = 'sharejs-text-ot'
_doc = { inflightSubmittedIds: new Set<string>() }
@@ -60,6 +63,14 @@ class FakeShareJsDoc extends EventEmitter {
return this.pendingOp
}
getInflightOpCreatedAt() {
return this.inflightOpCreatedAt
}
getPendingOpCreatedAt() {
return this.pendingOpCreatedAt
}
getInflightSubmittedIds() {
return this._doc.inflightSubmittedIds
}
@@ -151,6 +162,41 @@ describe('OfflineDocBackup', function () {
expect(readRecord()).to.be.null
})
it('backs up while still connected once saving stalls past the threshold', function () {
create()
doc.pendingOp = [{ i: 'x', p: 0 }]
doc.pendingOpCreatedAt = performance.now() - (STALL_AFTER_MS + 1000)
doc.trigger('change')
clock.tick(FLUSH_DELAY)
expect(doc.connection.state).to.equal('ok')
expect(readRecord()?.pendingOp).to.deep.equal([{ i: 'x', p: 0 }])
})
it('does not back up while connected and within the stall threshold', function () {
create()
doc.pendingOp = [{ i: 'x', p: 0 }]
doc.pendingOpCreatedAt = performance.now() - (STALL_AFTER_MS - 5000)
doc.trigger('change')
clock.tick(FLUSH_DELAY)
expect(readRecord()).to.be.null
})
it('uses the inflight op age (the oldest) to detect a stall', function () {
create()
doc.inflightOp = [{ i: 'sent', p: 0 }]
doc.inflightOpCreatedAt = performance.now() - (STALL_AFTER_MS + 1000)
doc.pendingOp = [{ i: 'queued', p: 5 }]
doc.pendingOpCreatedAt = performance.now()
doc.trigger('change')
clock.tick(FLUSH_DELAY)
const record = readRecord()
expect(record?.inflightOp).to.deep.equal([{ i: 'sent', p: 0 }])
expect(record?.pendingOp).to.deep.equal([{ i: 'queued', p: 5 }])
})
it('writes the baseline plus live ops when offline with buffered ops', function () {
create()
goOffline()