From 51a4b42f9c6d8a3adb40390ac8bde3f39ef8d550 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Feb 2026 20:02:14 +0000 Subject: [PATCH] feat(prekey): add destroy() method for proper resource cleanup Implements PreKeyManager.destroy() to prevent memory leaks during connection cleanup. Changes: - Added PreKeyManager.destroy() method that clears and pauses all PQueues - Exposed destroy() in SignalKeyStoreWithTransaction type - Integrated destroy() call in addTransactionCapability() to cleanup both PreKeyManager and keyQueues - Added keys.destroy() call in socket.ts end() function alongside other cleanup operations Benefits: - Prevents memory leaks from orphaned PQueues - Proper cleanup of PreKeyManager resources during disconnect - Consistent with existing cleanup pattern (circuit breakers, session manager) - Zero impact on active connections (only called during cleanup) Observability: - Added debug logs for tracking cleanup operations - Logs include queue type and cleanup status Cross-file analysis: - PreKeyManager instantiated in auth-utils.ts:130 - addTransactionCapability() called in socket.ts:499 - cleanup happens in socket.ts:836 (end function) https://claude.ai/code/session_33db9e93-e4c3-4859-9ff3-96d8864af1c4 --- src/Socket/socket.ts | 3 +++ src/Types/Auth.ts | 1 + src/Utils/auth-utils.ts | 19 +++++++++++++++++++ src/Utils/pre-key-manager.ts | 17 +++++++++++++++++ 4 files changed, 40 insertions(+) diff --git a/src/Socket/socket.ts b/src/Socket/socket.ts index 570f6b68..51cf581e 100644 --- a/src/Socket/socket.ts +++ b/src/Socket/socket.ts @@ -832,6 +832,9 @@ export const makeSocket = (config: SocketConfig) => { // Clean up unified session manager unifiedSessionManager?.destroy() + // Clean up transaction capability (PreKeyManager + queues) + keys.destroy?.() + ws.removeAllListeners('close') ws.removeAllListeners('open') ws.removeAllListeners('message') diff --git a/src/Types/Auth.ts b/src/Types/Auth.ts index 2e17ae97..870fbbdd 100644 --- a/src/Types/Auth.ts +++ b/src/Types/Auth.ts @@ -99,6 +99,7 @@ export type SignalKeyStore = { export type SignalKeyStoreWithTransaction = SignalKeyStore & { isInTransaction: () => boolean transaction(exec: () => Promise, key: string): Promise + destroy?: () => void } export type TransactionCapabilityOptions = { diff --git a/src/Utils/auth-utils.ts b/src/Utils/auth-utils.ts index 529d6ed2..6520d55b 100644 --- a/src/Utils/auth-utils.ts +++ b/src/Utils/auth-utils.ts @@ -339,6 +339,25 @@ export const addTransactionCapability = ( } finally { releaseTxMutexRef(key) } + }, + + /** + * Cleanup all resources (queues, managers) + * Should be called during connection cleanup + */ + destroy: () => { + logger.debug('🗑️ Cleaning up transaction capability resources') + preKeyManager.destroy() + + // Clear all key queues + keyQueues.forEach((queue, keyType) => { + queue.clear() + queue.pause() + logger.debug(`Queue for ${keyType} cleared and paused`) + }) + keyQueues.clear() + + logger.debug('Transaction capability cleanup completed') } } } diff --git a/src/Utils/pre-key-manager.ts b/src/Utils/pre-key-manager.ts index 635a8195..858cab77 100644 --- a/src/Utils/pre-key-manager.ts +++ b/src/Utils/pre-key-manager.ts @@ -123,4 +123,21 @@ export class PreKeyManager { } }) } + + /** + * Cleanup all queues and resources + * Should be called during connection cleanup to prevent memory leaks + */ + destroy(): void { + this.logger.debug('🗑️ Destroying PreKeyManager') + + this.queues.forEach((queue, keyType) => { + queue.clear() + queue.pause() + this.logger.debug(`Queue for ${keyType} cleared and paused`) + }) + + this.queues.clear() + this.logger.debug('PreKeyManager destroyed - all queues cleaned up') + } }