Files
crowd-funder-for-time-pwa/doc/WORKER_ONLY_DATABASE_IMPLEMENTATION.md
Matthew Raymer f53542d2ff Fix InviteOneAcceptView migration fence; remove USE_DEXIE_DB dependency
- Remove USE_DEXIE_DB import from app.ts constants
- Update InviteOneAcceptView to use PlatformServiceMixin pattern
- Remove legacy Dexie database access code
- Move WORKER_ONLY_DATABASE_IMPLEMENTATION.md to doc/ directory
- Remerge changes from master router/index.ts

Fixes Electron build failure caused by missing USE_DEXIE_DB export.
2025-07-15 07:20:54 +00:00

11 KiB

Worker-Only Database Implementation for Web Platform

Overview

This implementation fixes the double migration issue in the TimeSafari web platform by implementing worker-only database access, similar to the Capacitor platform architecture.

Problem Solved

Before: Web platform had dual database contexts:

  • Worker thread: registerSQLWorker.jsAbsurdSqlDatabaseService.initialize() → migrations run
  • Main thread: WebPlatformService.dbQuery()databaseService.query() → migrations run AGAIN

After: Single database context:

  • Worker thread: Handles ALL database operations and initializes once
  • Main thread: Sends messages to worker, no direct database access

Architecture Changes

1. Message-Based Communication

// Main Thread (WebPlatformService)
await this.sendWorkerMessage<QueryResult>({
  type: "query",
  sql: "SELECT * FROM users",
  params: []
});

// Worker Thread (registerSQLWorker.js)
onmessage = async (event) => {
  const { id, type, sql, params } = event.data;
  if (type === "query") {
    const result = await databaseService.query(sql, params);
    postMessage({ id, type: "success", data: { result } });
  }
};

2. Type-Safe Worker Messages

// src/interfaces/worker-messages.ts
export interface QueryRequest extends BaseWorkerMessage {
  type: "query";
  sql: string;
  params?: unknown[];
}

export type WorkerRequest =
  | QueryRequest
  | ExecRequest
  | GetOneRowRequest
  | InitRequest
  | PingRequest;

3. Circular Dependency Resolution

🔥 Critical Fix: Stack Overflow Prevention

Problem: Circular module dependency caused infinite recursion:

  • WebPlatformService constructor → creates Worker
  • Worker loads registerSQLWorker.js → imports databaseService
  • Module resolution creates circular dependency → Stack Overflow

Solution: Lazy Loading in Worker

// Before (caused stack overflow)
import databaseService from "./services/AbsurdSqlDatabaseService";

// After (fixed)
let databaseService = null;

async function getDatabaseService() {
  if (!databaseService) {
    // Dynamic import prevents circular dependency
    const { default: service } = await import("./services/AbsurdSqlDatabaseService");
    databaseService = service;
  }
  return databaseService;
}

Key Changes for Stack Overflow Fix:

  • Removed top-level import of database service
  • Added lazy loading with dynamic import
  • Updated all handlers to use await getDatabaseService()
  • Removed auto-initialization that triggered immediate loading
  • Database service only loads when first database operation occurs

Implementation Details

1. WebPlatformService Changes

  • Removed direct database imports
  • Added worker message handling
  • Implemented timeout and error handling
  • All database methods now proxy to worker

2. Worker Thread Changes

  • Added message-based operation handling
  • Implemented lazy loading for database service
  • Added proper error handling and response formatting
  • Fixed circular dependency with dynamic imports

3. Main Thread Changes

  • Removed duplicate worker creation in main.web.ts
  • WebPlatformService now manages single worker instance
  • Added Safari compatibility with initBackend()

Files Modified

  1. src/interfaces/worker-messages.ts (NEW)

    • Type definitions for worker communication
    • Request and response message interfaces
  2. src/registerSQLWorker.js (MAJOR REWRITE)

    • Message-based operation handling
    • Fixed circular dependency with lazy loading
    • Proper error handling and response formatting
  3. src/services/platforms/WebPlatformService.ts (MAJOR REWRITE)

    • Worker-only database access
    • Message sending and response handling
    • Timeout and error management
  4. src/main.web.ts (SIMPLIFIED)

    • Removed duplicate worker creation
    • Simplified initialization flow
  5. WORKER_ONLY_DATABASE_IMPLEMENTATION.md (NEW)

    • Complete documentation of changes

Benefits

Fixes Double Migration Issue

  • Database migrations now run only once in worker thread
  • No duplicate initialization between main thread and worker

Prevents Stack Overflow

  • Circular dependency resolved with lazy loading
  • Worker loads immediately without triggering database import
  • Database service loads on-demand when first operation occurs

Improved Performance

  • Single database connection
  • No redundant operations
  • Better resource utilization

Better Error Handling

  • Centralized error handling in worker
  • Type-safe message communication
  • Proper timeout handling

Consistent Architecture

  • Matches Capacitor platform pattern
  • Single-threaded database access
  • Clear separation of concerns

Testing Verification

After implementation, you should see:

  1. Worker Loading:

    [SQLWorker] Worker loaded, ready to receive messages
    
  2. Database Initialization (only on first operation):

    [SQLWorker] Starting database initialization...
    [SQLWorker] Database initialization completed successfully
    
  3. No Stack Overflow: Application starts without infinite recursion

  4. Single Migration Run: Database migrations execute only once

  5. Functional Database: All queries, inserts, and updates work correctly

Migration from Previous Implementation

If upgrading from the dual-context implementation:

  1. Remove Direct Database Imports: No more import databaseService in main thread
  2. Update Database Calls: Use platform service methods instead of direct database calls
  3. Handle Async Operations: All database operations are now async message-based
  4. Error Handling: Update error handling to work with worker responses

Security Considerations

  • Worker thread isolates database operations
  • Message validation prevents malformed requests
  • Timeout handling prevents hanging operations
  • Type safety reduces runtime errors

Performance Notes

  • Initial worker creation has minimal overhead
  • Database operations have message passing overhead (negligible)
  • Single database connection is more efficient than dual connections
  • Lazy loading reduces startup time

Migration Execution Flow

Before (Problematic)

┌──────────────  ───┐    ┌─────────────────┐
│   Main Thread     │    │  Worker Thread  │
│                   │    │                 │
│ WebPlatformService│    │registerSQLWorker│
│        ↓          │    │        ↓        │
│ databaseService   │    │ databaseService │
│   (Instance A)    │    │   (Instance B)  │
│        ↓          │    │        ↓        │
│  [Run Migrations] │    │[Run Migrations] │ ← DUPLICATE!
└───────────────  ──┘    └─────────────────┘

After (Fixed)

┌───────────────   ──┐    ┌─────────────────┐
│   Main Thread      │    │  Worker Thread  │
│                    │    │                 │
│ WebPlatformService │───→│registerSQLWorker│
│                    │    │        ↓        │
│   [Send Messages]  │    │ databaseService │
│                    │    │(Single Instance)│
│                    │    │        ↓        │
│                    │    │[Run Migrations] │ ← ONCE ONLY!
└───────────────   ──┘    └─────────────────┘

New Security Considerations

1. Message Validation

  • All worker messages validated for required fields
  • Unknown message types rejected with errors
  • Proper error responses prevent information leakage

2. Timeout Protection

  • 30-second timeout prevents hung operations
  • Automatic cleanup of pending messages
  • Worker health checks via ping/pong

3. Error Sanitization

  • Error messages logged but not exposed raw to main thread
  • Stack traces included only in development
  • Graceful handling of worker failures

Testing Considerations

1. Unit Tests Needed

  • Worker message handling
  • WebPlatformService worker communication
  • Error handling and timeouts
  • Migration execution (should run once only)

2. Integration Tests

  • End-to-end database operations
  • Worker lifecycle management
  • Cross-browser compatibility (especially Safari)

3. Performance Tests

  • Message passing overhead
  • Database operation throughput
  • Memory usage with worker communication

Browser Compatibility

1. Modern Browsers

  • Chrome/Edge: Full SharedArrayBuffer support
  • Firefox: Full SharedArrayBuffer support (with headers)
  • Safari: Uses IndexedDB fallback via initBackend()

2. Required Headers

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

Deployment Notes

1. Development

  • Enhanced logging shows worker message flow
  • Clear separation between worker and main thread logs
  • Easy debugging via browser DevTools

2. Production

  • Reduced logging overhead
  • Optimized message passing
  • Proper error reporting without sensitive data

Future Enhancements

1. Potential Optimizations

  • Message batching for bulk operations
  • Connection pooling simulation
  • Persistent worker state management

2. Additional Features

  • Database backup/restore via worker
  • Schema introspection commands
  • Performance monitoring hooks

Rollback Plan

If issues arise, rollback involves:

  1. Restore original WebPlatformService.ts
  2. Restore original registerSQLWorker.js
  3. Restore original main.web.ts
  4. Remove worker-messages.ts interface

Commit Messages

git add src/interfaces/worker-messages.ts
git commit -m "Add worker message interface for type-safe database communication

- Define TypeScript interfaces for worker request/response messages
- Include query, exec, getOneRow, init, and ping message types
- Provide type safety for web platform worker messaging"

git add src/registerSQLWorker.js
git commit -m "Implement message-based worker for single-point database access

- Replace simple auto-init with comprehensive message handler
- Add support for query, exec, getOneRow, init, ping operations
- Implement proper error handling and response management
- Ensure single database initialization point to prevent double migrations"

git add src/services/platforms/WebPlatformService.ts
git commit -m "Migrate WebPlatformService to worker-only database access

- Remove direct databaseService import to prevent dual context issue
- Implement worker-based messaging for all database operations
- Add worker lifecycle management with initialization tracking
- Include message timeout and error handling for reliability
- Add Safari compatibility with initBackend call"

git add src/main.web.ts
git commit -m "Remove duplicate worker creation from main.web.ts

- Worker initialization now handled by WebPlatformService
- Prevents duplicate worker creation and database contexts
- Simplifies main thread initialization"

git add WORKER_ONLY_DATABASE_IMPLEMENTATION.md
git commit -m "Document worker-only database implementation

- Comprehensive documentation of architecture changes
- Explain problem solved and benefits achieved
- Include security considerations and testing requirements"