From f06b6aa367ed9ea519db9ef634a9296905b55fbc Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Thu, 3 Jul 2025 09:22:19 +0000 Subject: [PATCH] Fix circular dependency in logging during initialization - Add initialization phase detection to logger (2-second delay) - Prevent database logging during critical startup phase - Use console logging for critical startup messages to avoid circular dependency - Add manual initialization control functions (markInitializationComplete, isInitializationPhase) - Filter initialization-related messages from database logging Files modified: - src/utils/logger.ts: Add initialization state tracking and filtering - src/registerSQLWorker.js: Use console for critical startup message - src/services/PlatformServiceFactory.ts: Use console for singleton creation message - src/services/platforms/WebPlatformService.ts: Use console for worker context message Resolves circular dependency where logging tried to access database during platform service initialization, causing infinite loops with [DB-PREVENTED-INFO] messages. --- src/registerSQLWorker.js | 4 +- src/services/PlatformServiceFactory.ts | 5 +- src/services/platforms/WebPlatformService.ts | 4 +- src/utils/logger.ts | 83 ++++++++++++++++---- 4 files changed, 75 insertions(+), 21 deletions(-) diff --git a/src/registerSQLWorker.js b/src/registerSQLWorker.js index 5379388f..890e1762 100644 --- a/src/registerSQLWorker.js +++ b/src/registerSQLWorker.js @@ -215,4 +215,6 @@ onerror = function (error) { * Auto-initialize on worker startup (removed to prevent circular dependency) * Initialization now happens on first database operation */ -logger.log("[SQLWorker] Worker loaded, ready to receive messages"); +// Use console for critical startup message to avoid circular dependency +// eslint-disable-next-line no-console +console.log("[SQLWorker] Worker loaded, ready to receive messages"); diff --git a/src/services/PlatformServiceFactory.ts b/src/services/PlatformServiceFactory.ts index 4ba8a7cb..88517e84 100644 --- a/src/services/PlatformServiceFactory.ts +++ b/src/services/PlatformServiceFactory.ts @@ -1,7 +1,6 @@ import { PlatformService } from "./PlatformService"; import { WebPlatformService } from "./platforms/WebPlatformService"; import { CapacitorPlatformService } from "./platforms/CapacitorPlatformService"; -import { logger } from "../utils/logger"; /** * Factory class for creating platform-specific service implementations. @@ -42,7 +41,9 @@ export class PlatformServiceFactory { const platform = process.env.VITE_PLATFORM || "web"; if (!PlatformServiceFactory.creationLogged) { - logger.log( + // Use console for critical startup message to avoid circular dependency + // eslint-disable-next-line no-console + console.log( `[PlatformServiceFactory] Creating singleton instance for platform: ${platform}`, ); PlatformServiceFactory.creationLogged = true; diff --git a/src/services/platforms/WebPlatformService.ts b/src/services/platforms/WebPlatformService.ts index 2401e1b5..7463ad30 100644 --- a/src/services/platforms/WebPlatformService.ts +++ b/src/services/platforms/WebPlatformService.ts @@ -97,7 +97,9 @@ export class WebPlatformService implements PlatformService { } } else { // We're in a worker context - skip initBackend call - logger.log( + // Use console for critical startup message to avoid circular dependency + // eslint-disable-next-line no-console + console.log( "[WebPlatformService] Skipping initBackend call in worker context", ); } diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 99625f69..59f3f907 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -23,6 +23,40 @@ export function safeStringify(obj: unknown) { const isElectron = process.env.VITE_PLATFORM === "electron"; const isProduction = process.env.NODE_ENV === "production"; +// Track initialization state to prevent circular dependencies +let isInitializing = true; + +// Mark initialization as complete after a delay to allow all services to start +setTimeout(() => { + isInitializing = false; +}, 2000); // 2 second delay to allow all services to initialize + +// Function to check if we should skip database logging during initialization +function shouldSkipDatabaseLogging(message: string): boolean { + // Skip during initialization phase + if (isInitializing) { + return true; + } + + // Skip specific initialization-related messages even after initialization + const initializationMessages = [ + "[PlatformServiceFactory]", + "[SQLWorker]", + "[WebPlatformService]", + "[CapacitorPlatformService]", + "[CapacitorMigration]", + "[DB-Integrity]", + "[Migration]", + "[IndexedDBMigrationService]", + "Creating singleton instance", + "Worker loaded", + "Worker initialized", + "Platform service", + ]; + + return initializationMessages.some((pattern) => message.includes(pattern)); +} + export const logger = { debug: (message: string, ...args: unknown[]) => { // Debug logs are very verbose - only show in development mode for web @@ -42,15 +76,8 @@ export const logger = { console.log(message, ...args); } - // Only log to database for important messages (not routine operations) - // Skip database logging for migration messages to avoid circular dependency - if ( - !message.includes("[CapacitorPlatformService]") && - !message.includes("[CapacitorMigration]") && - !message.includes("[DB-Integrity]") && - !message.includes("[Migration]") && - !message.includes("[IndexedDBMigrationService]") - ) { + // Skip database logging during initialization or for initialization-related messages + if (!shouldSkipDatabaseLogging(message)) { const argsString = args.length > 0 ? " - " + safeStringify(args) : ""; logToDb(message + argsString); } @@ -63,6 +90,10 @@ export const logger = { ) { // eslint-disable-next-line no-console console.info(message, ...args); + } + + // Skip database logging during initialization or for initialization-related messages + if (!shouldSkipDatabaseLogging(message)) { const argsString = args.length > 0 ? " - " + safeStringify(args) : ""; logToDb(message + argsString); } @@ -74,26 +105,44 @@ export const logger = { console.warn(message, ...args); } - // Log warnings to database, but filter out routine operations - if (!message.includes("[CapacitorPlatformService]")) { + // Skip database logging during initialization or for initialization-related messages + if (!shouldSkipDatabaseLogging(message)) { const argsString = args.length > 0 ? " - " + safeStringify(args) : ""; logToDb(message + argsString); } }, error: (message: string, ...args: unknown[]) => { - // Errors will always be logged + // Errors will always be logged to console // eslint-disable-next-line no-console console.error(message, ...args); - const messageString = safeStringify(message); - const argsString = args.length > 0 ? safeStringify(args) : ""; - logToDb(messageString + argsString); + + // Skip database logging during initialization or for initialization-related messages + if (!shouldSkipDatabaseLogging(message)) { + const messageString = safeStringify(message); + const argsString = args.length > 0 ? safeStringify(args) : ""; + logToDb(messageString + argsString); + } }, }; +// Function to manually mark initialization as complete +export function markInitializationComplete(): void { + isInitializing = false; +} + +// Function to check initialization status +export function isInitializationPhase(): boolean { + return isInitializing; +} + // Add CommonJS export for Electron if (typeof module !== "undefined" && module.exports) { - module.exports = { logger }; + module.exports = { + logger, + markInitializationComplete, + isInitializationPhase, + }; } // Add default export for ESM -export default { logger }; +export default { logger, markInitializationComplete, isInitializationPhase };