From f94ebcc8bf71e2dd1bfcb1d1882265ef54cba494 Mon Sep 17 00:00:00 2001 From: EYHN Date: Wed, 4 Dec 2024 15:53:07 +0900 Subject: [PATCH] fix(infra): memory leak --- .../common/infra/src/framework/core/event.ts | 17 ++++++-- .../infra/src/framework/core/provider.ts | 2 + .../modules/workspace/entities/workspace.ts | 5 +++ .../src/modules/workspace/services/repo.ts | 2 +- .../modules/workspace/services/workspace.ts | 4 ++ .../workspace/testing/testing-provider.ts | 2 + packages/common/infra/src/sync/awareness.ts | 4 +- .../presets/_common/utils/markdown-utils.ts | 1 + .../components/workspace-selector/menu.tsx | 2 +- .../docs-search/entities/docs-indexer.ts | 40 ++++++++++--------- .../modules/docs-search/worker/out-worker.ts | 2 +- .../modules/workspace-engine/impls/cloud.ts | 1 + .../modules/workspace-engine/impls/local.ts | 1 + 13 files changed, 57 insertions(+), 26 deletions(-) diff --git a/packages/common/infra/src/framework/core/event.ts b/packages/common/infra/src/framework/core/event.ts index 6fe5b6f390115..c5b2b8e3be650 100644 --- a/packages/common/infra/src/framework/core/event.ts +++ b/packages/common/infra/src/framework/core/event.ts @@ -48,16 +48,16 @@ export class EventBus { this.listeners[event.id].push(listener); const off = this.parent?.on(event, listener); return () => { - this.off(event, listener); off?.(); + this.off(event.id, listener); }; } - off(event: FrameworkEvent, listener: (event: T) => void) { - if (!this.listeners[event.id]) { + private off(eventId: string, listener: (event: any) => void) { + if (!this.listeners[eventId]) { return; } - this.listeners[event.id] = this.listeners[event.id].filter( + this.listeners[eventId] = this.listeners[eventId].filter( l => l !== listener ); } @@ -76,6 +76,15 @@ export class EventBus { } }); } + + dispose(): void { + for (const eventId of Object.keys(this.listeners)) { + for (const listener of this.listeners[eventId]) { + this.parent?.off(eventId, listener); + } + } + this.listeners = {}; + } } interface EventHandler { diff --git a/packages/common/infra/src/framework/core/provider.ts b/packages/common/infra/src/framework/core/provider.ts index d64c75a65de41..2c8cd662e2102 100644 --- a/packages/common/infra/src/framework/core/provider.ts +++ b/packages/common/infra/src/framework/core/provider.ts @@ -130,6 +130,7 @@ export class ComponentCachePool { } } } + this.cache.clear(); } [Symbol.dispose]() { @@ -318,5 +319,6 @@ export class BasicFrameworkProvider extends FrameworkProvider { } this.disposed = true; this.cache.dispose(); + this.eventBus.dispose(); } } diff --git a/packages/common/infra/src/modules/workspace/entities/workspace.ts b/packages/common/infra/src/modules/workspace/entities/workspace.ts index 8eaac10a307c4..de04b2fd3cf4f 100644 --- a/packages/common/infra/src/modules/workspace/entities/workspace.ts +++ b/packages/common/infra/src/modules/workspace/entities/workspace.ts @@ -82,4 +82,9 @@ export class Workspace extends Entity { }), undefined ); + + override dispose(): void { + this.docCollection.awarenessStore.destroy(); + (this.docCollection.awarenessStore.awareness as Awareness).destroy(); + } } diff --git a/packages/common/infra/src/modules/workspace/services/repo.ts b/packages/common/infra/src/modules/workspace/services/repo.ts index 5ff50fcf05678..1fee2f1cfa85d 100644 --- a/packages/common/infra/src/modules/workspace/services/repo.ts +++ b/packages/common/infra/src/modules/workspace/services/repo.ts @@ -49,7 +49,7 @@ export class WorkspaceRepositoryService extends Service { return { workspace, dispose: () => { - workspace.dispose(); + workspace.scope.dispose(); }, }; } diff --git a/packages/common/infra/src/modules/workspace/services/workspace.ts b/packages/common/infra/src/modules/workspace/services/workspace.ts index f431deef3bfd7..40ae067de7f09 100644 --- a/packages/common/infra/src/modules/workspace/services/workspace.ts +++ b/packages/common/infra/src/modules/workspace/services/workspace.ts @@ -10,4 +10,8 @@ export class WorkspaceService extends Service { } return this._workspace; } + + override dispose(): void { + this._workspace?.dispose(); + } } diff --git a/packages/common/infra/src/modules/workspace/testing/testing-provider.ts b/packages/common/infra/src/modules/workspace/testing/testing-provider.ts index 8ae30dcbc6956..cfe2c48598be4 100644 --- a/packages/common/infra/src/modules/workspace/testing/testing-provider.ts +++ b/packages/common/infra/src/modules/workspace/testing/testing-provider.ts @@ -94,6 +94,8 @@ class TestingWorkspaceLocalProvider implements WorkspaceFlavourProvider { applyUpdate(bs.doc, data); + bs.awarenessStore.awareness.destroy(); + return { name: bs.meta.name, avatar: bs.meta.avatar, diff --git a/packages/common/infra/src/sync/awareness.ts b/packages/common/infra/src/sync/awareness.ts index 395de22ea81db..351077c4f9927 100644 --- a/packages/common/infra/src/sync/awareness.ts +++ b/packages/common/infra/src/sync/awareness.ts @@ -7,7 +7,9 @@ export interface AwarenessConnection { } export class AwarenessEngine { - constructor(public readonly connections: AwarenessConnection[]) {} + constructor(public readonly connections: AwarenessConnection[]) { + console.log('AwarenessEngine', connections); + } connect(awareness: Awareness) { this.connections.forEach(connection => connection.connect(awareness)); diff --git a/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts b/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts index 1eba15ce163d7..b98d949cf992d 100644 --- a/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts +++ b/packages/frontend/core/src/blocksuite/presets/_common/utils/markdown-utils.ts @@ -194,6 +194,7 @@ export async function markDownToDoc( const collection = new DocCollection({ schema, }); + collection.awarenessStore.awareness.destroy(); collection.meta.initialize(); const middlewares = [defaultImageProxyMiddleware]; if (additionalMiddlewares) { diff --git a/packages/frontend/core/src/mobile/components/workspace-selector/menu.tsx b/packages/frontend/core/src/mobile/components/workspace-selector/menu.tsx index 42d757348d89a..5d21ac7caed32 100644 --- a/packages/frontend/core/src/mobile/components/workspace-selector/menu.tsx +++ b/packages/frontend/core/src/mobile/components/workspace-selector/menu.tsx @@ -61,7 +61,7 @@ const WorkspaceList = ({ const toggleWorkspace = useCallback( (id: string) => { if (id !== currentWorkspace.id) { - jumpToPage(id, 'all'); + jumpToPage(id, 'home'); } onClose?.(); }, diff --git a/packages/frontend/core/src/modules/docs-search/entities/docs-indexer.ts b/packages/frontend/core/src/modules/docs-search/entities/docs-indexer.ts index 205e5920ff520..8ce37254a5143 100644 --- a/packages/frontend/core/src/modules/docs-search/entities/docs-indexer.ts +++ b/packages/frontend/core/src/modules/docs-search/entities/docs-indexer.ts @@ -85,24 +85,26 @@ export class DocsIndexer extends Entity { } setupListener() { - this.workspaceEngine.doc.storage.eventBus.on(event => { - if (WorkspaceDBService.isDBDocId(event.docId)) { - // skip db doc - return; - } - if (event.clientId === this.workspaceEngine.doc.clientId) { - this.jobQueue - .enqueue([ - { - batchKey: event.docId, - payload: { storageDocId: event.docId }, - }, - ]) - .catch(err => { - console.error('Error enqueueing job', err); - }); - } - }); + this.disposables.push( + this.workspaceEngine.doc.storage.eventBus.on(event => { + if (WorkspaceDBService.isDBDocId(event.docId)) { + // skip db doc + return; + } + if (event.clientId === this.workspaceEngine.doc.clientId) { + this.jobQueue + .enqueue([ + { + batchKey: event.docId, + payload: { storageDocId: event.docId }, + }, + ]) + .catch(err => { + console.error('Error enqueueing job', err); + }); + } + }) + ); } async execJob(jobs: Job[], signal: AbortSignal) { @@ -298,6 +300,8 @@ export class DocsIndexer extends Entity { } override dispose(): void { + super.dispose(); this.runner.stop(); + this.worker?.dispose(); } } diff --git a/packages/frontend/core/src/modules/docs-search/worker/out-worker.ts b/packages/frontend/core/src/modules/docs-search/worker/out-worker.ts index a41d3a3132810..4c2de87219bcd 100644 --- a/packages/frontend/core/src/modules/docs-search/worker/out-worker.ts +++ b/packages/frontend/core/src/modules/docs-search/worker/out-worker.ts @@ -95,8 +95,8 @@ export async function createWorker(abort: AbortSignal) { }); }, dispose: () => { - worker.terminate(); terminateAbort.abort(MANUALLY_STOP); + worker.terminate(); }, }; } diff --git a/packages/frontend/core/src/modules/workspace-engine/impls/cloud.ts b/packages/frontend/core/src/modules/workspace-engine/impls/cloud.ts index fe5046736df11..976e6bf5dea58 100644 --- a/packages/frontend/core/src/modules/workspace-engine/impls/cloud.ts +++ b/packages/frontend/core/src/modules/workspace-engine/impls/cloud.ts @@ -240,6 +240,7 @@ class CloudWorkspaceFlavourProvider implements WorkspaceFlavourProvider { id, schema: getAFFiNEWorkspaceSchema(), }); + bs.awarenessStore.awareness.destroy(); if (localData) applyUpdate(bs.doc, localData); if (cloudData) applyUpdate(bs.doc, cloudData.data); diff --git a/packages/frontend/core/src/modules/workspace-engine/impls/local.ts b/packages/frontend/core/src/modules/workspace-engine/impls/local.ts index 79fe8c71946dd..c54ce2f9116e6 100644 --- a/packages/frontend/core/src/modules/workspace-engine/impls/local.ts +++ b/packages/frontend/core/src/modules/workspace-engine/impls/local.ts @@ -162,6 +162,7 @@ class LocalWorkspaceFlavourProvider implements WorkspaceFlavourProvider { id, schema: getAFFiNEWorkspaceSchema(), }); + bs.awarenessStore.awareness.destroy(); if (localData) applyUpdate(bs.doc, localData);