fix(schedule): close concurrent durability gaps
This commit is contained in:
@@ -403,6 +403,9 @@ export class Session implements SessionFace {
|
||||
try {
|
||||
const { result } = await this.history({ beforeSeq: loading.beforeSeq, maxMessages: PAGE_MESSAGES })
|
||||
if (this.loadingOlder !== loading) return
|
||||
// A concurrent gap repair may replace the window with a newer tail page.
|
||||
// The captured older page no longer adjoins that window and must be dropped.
|
||||
if (this.baseSeq !== loading.beforeSeq) return
|
||||
if (!result.ok) return // keep the window as-is; do not overwrite openError (open already succeeded)
|
||||
const older = result.value.events
|
||||
if (older.length === 0) {
|
||||
|
||||
@@ -286,6 +286,40 @@ describe('late event views', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('drops an older page after a concurrent gap repair advances the window base', async () => {
|
||||
const { api, session } = makeSession()
|
||||
api.onHistory = () => histResponse(logRange(50, 100), true)
|
||||
await session.open()
|
||||
|
||||
const repair = deferred<Awaited<ReturnType<FakeApiClient['onHistory']>>>()
|
||||
const page = deferred<Awaited<ReturnType<FakeApiClient['onHistory']>>>()
|
||||
api.onHistory = payload => payload.beforeSeq === undefined ? repair.promise : page.promise
|
||||
const gapTail = ev.user(200, '修复后的新窗口')
|
||||
session.handleMuxEnvelope('gap' as never, {
|
||||
type: 'session/event', sessionId: SID, event: gapTail,
|
||||
})
|
||||
await vi.waitFor(() => {
|
||||
expect(api.callsOf('session.history')).toHaveLength(2)
|
||||
})
|
||||
|
||||
const loading = session.loadOlder()
|
||||
repair.resolve(ok({
|
||||
events: entries([...logRange(150, 200), gapTail]) as never[],
|
||||
hasMore: true,
|
||||
}))
|
||||
await vi.waitFor(() => {
|
||||
expect(session.getSnapshot().nodes.map(node => node.seq)).toEqual([200])
|
||||
})
|
||||
|
||||
page.resolve(ok({
|
||||
events: entries([...logRange(0, 44), ...plainTurn(44, 0, '陈旧问题', '陈旧回答')]) as never[],
|
||||
hasMore: false,
|
||||
}))
|
||||
await loading
|
||||
expect(session.getSnapshot()).toMatchObject({ hasMore: true })
|
||||
expect(session.getSnapshot().nodes.map(node => node.seq)).toEqual([200])
|
||||
})
|
||||
|
||||
it('resyncs when repeated older-page late views disagree on event identity', async () => {
|
||||
const { api, session } = makeSession()
|
||||
const newer = logRange(6, 12)
|
||||
|
||||
Reference in New Issue
Block a user