Clean up verbose console.log statements that were cluttering test output. The function now performs the same operations without debug noise, making test runs cleaner and more focused on actual test results.
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.js→AbsurdSqlDatabaseService.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:
WebPlatformServiceconstructor → creates Worker- Worker loads
registerSQLWorker.js→ importsdatabaseService - 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
-
src/interfaces/worker-messages.ts (NEW)
- Type definitions for worker communication
- Request and response message interfaces
-
src/registerSQLWorker.js (MAJOR REWRITE)
- Message-based operation handling
- Fixed circular dependency with lazy loading
- Proper error handling and response formatting
-
src/services/platforms/WebPlatformService.ts (MAJOR REWRITE)
- Worker-only database access
- Message sending and response handling
- Timeout and error management
-
src/main.web.ts (SIMPLIFIED)
- Removed duplicate worker creation
- Simplified initialization flow
-
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:
-
Worker Loading:
[SQLWorker] Worker loaded, ready to receive messages -
Database Initialization (only on first operation):
[SQLWorker] Starting database initialization... [SQLWorker] Database initialization completed successfully -
No Stack Overflow: Application starts without infinite recursion
-
Single Migration Run: Database migrations execute only once
-
Functional Database: All queries, inserts, and updates work correctly
Migration from Previous Implementation
If upgrading from the dual-context implementation:
- Remove Direct Database Imports: No more
import databaseServicein main thread - Update Database Calls: Use platform service methods instead of direct database calls
- Handle Async Operations: All database operations are now async message-based
- 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:
- Restore original
WebPlatformService.ts - Restore original
registerSQLWorker.js - Restore original
main.web.ts - Remove
worker-messages.tsinterface
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"