fix(fig): finalize worker cleanup semantics

- Retain worker graphs only for lazy first-page imports\n- Make termination idempotent\n- Wait on deterministic population telemetry in E2E coverage
This commit is contained in:
Danila Poyarkov 2026-08-07 14:43:59 +03:00
parent a5a744843f
commit 02400a84b9
3 changed files with 18 additions and 9 deletions

View file

@ -60,10 +60,11 @@ self.onmessage = (event: MessageEvent<WorkerRequest>) => {
const { nodeChanges, blobs, images, figKiwiVersion, figSchemaDeflated } = parseFigBuffer(
parseRequest.buffer
)
graph = importNodeChanges(nodeChanges, blobs, new Map(images), parseRequest.options)
graph.figKiwiVersion = figKiwiVersion
graph.figSchemaDeflated = figSchemaDeflated
const serialized = serializeSceneGraph(graph)
const parsedGraph = importNodeChanges(nodeChanges, blobs, new Map(images), parseRequest.options)
parsedGraph.figKiwiVersion = figKiwiVersion
parsedGraph.figSchemaDeflated = figSchemaDeflated
graph = parseRequest.options?.populate === 'first-page' ? parsedGraph : undefined
const serialized = serializeSceneGraph(parsedGraph)
const transfer =
parseRequest.options?.populate === 'first-page'
? []

View file

@ -78,6 +78,7 @@ function createPopulationWorkerClient(graph: SceneGraph, worker: Worker): FigPop
>()
let revision = 0
let stale = false
let disposed = false
let applyingDelta = false
const invalidate = () => {
if (applyingDelta || stale) return
@ -161,6 +162,8 @@ function createPopulationWorkerClient(graph: SceneGraph, worker: Worker): FigPop
})
},
terminate() {
if (disposed) return
disposed = true
emitTelemetry({ event: 'terminated' })
fail(false)
}

View file

@ -23,15 +23,20 @@ test('populates a real lazy FIG page in the retained parse worker', async () =>
})
if (!targetPageId) throw new Error('Target page not found')
const loading = editor.page.getByTestId('canvas-loading')
const switchPromise = editor.page.evaluate((pageId) => {
await editor.page.evaluate((pageId) => {
const store = window.openPencil?.getStore?.()
if (!store) throw new Error('OpenPencil store not initialized')
return store.switchPage(pageId)
}, targetPageId)
await expect(loading).toBeVisible()
await switchPromise
await expect(loading).not.toBeVisible()
await expect
.poll(() =>
editor.page.evaluate(() =>
(Reflect.get(window, 'figPopulationWorkerEvents') as Array<{ event: string }>).some(
({ event }) => event === 'populate'
)
)
)
.toBe(true)
const currentPage = await editor.page.evaluate(() => {
const store = window.openPencil?.getStore?.()