feat(browser): add graceful shutdown with WAL checkpoint and history flush
- commit
- e9a6f11e267d6dcefde24546dcdc1b4db963a567
- author
- bnema · · 2025-10-23 21:52 UTC
- committer
- bnema · · 2025-10-24 17:33 UTC
- parent
- a38f745
- signature
- unsigned
1 file · +26 -2
M internal/app/browser/browser.go +26 -2
| @@ -1,6 +1,7 @@ | |||
| 1 | 1 | package browser | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | + | "context" | |
| 4 | 5 | "database/sql" | |
| 5 | 6 | "embed" | |
| 6 | 7 | "log" | |
| @@ -136,6 +137,12 @@ func (app *BrowserApp) Initialize() error { | |||
| 136 | 137 | app.parserService = services.NewParserService(app.config, app.queries) | |
| 137 | 138 | app.browserService = services.NewBrowserService(app.config, app.queries) | |
| 138 | 139 | ||
| 140 | + | // Load zoom levels into in-memory cache for fast page transitions | |
| 141 | + | if err := app.browserService.LoadZoomCacheFromDB(context.Background()); err != nil { | |
| 142 | + | log.Printf("Warning: failed to load zoom cache: %v", err) | |
| 143 | + | // Non-fatal - zoom will fall back to defaults | |
| 144 | + | } | |
| 145 | + | ||
| 139 | 146 | // Initialize handlers | |
| 140 | 147 | app.schemeHandler = api.NewSchemeHandler(app.assets, app.parserService, app.browserService) | |
| 141 | 148 | app.messageHandler = messaging.NewHandler(app.parserService, app.browserService) | |
| @@ -211,11 +218,28 @@ func (app *BrowserApp) cleanup() { | |||
| 211 | 218 | app.workspace = nil | |
| 212 | 219 | } | |
| 213 | 220 | ||
| 214 | - | // Close database last | |
| 221 | + | // Flush pending history writes before closing database | |
| 222 | + | if app.browserService != nil { | |
| 223 | + | log.Printf("Flushing pending history writes...") | |
| 224 | + | app.browserService.FlushHistoryQueue() | |
| 225 | + | } | |
| 226 | + | ||
| 227 | + | // Close database with WAL checkpoint | |
| 215 | 228 | if app.database != nil { | |
| 216 | - | log.Printf("Closing database") | |
| 229 | + | log.Printf("Performing WAL checkpoint and closing database...") | |
| 230 | + | ||
| 231 | + | // Run WAL checkpoint to commit all pending writes and truncate WAL file | |
| 232 | + | if _, err := app.database.Exec("PRAGMA wal_checkpoint(TRUNCATE)"); err != nil { | |
| 233 | + | log.Printf("Warning: WAL checkpoint failed: %v", err) | |
| 234 | + | } else { | |
| 235 | + | log.Printf("WAL checkpoint completed successfully") | |
| 236 | + | } | |
| 237 | + | ||
| 238 | + | // Close database connection | |
| 217 | 239 | if closeErr := app.database.Close(); closeErr != nil { | |
| 218 | 240 | log.Printf("Warning: failed to close database: %v", closeErr) | |
| 241 | + | } else { | |
| 242 | + | log.Printf("Database closed successfully") | |
| 219 | 243 | } | |
| 220 | 244 | } | |
| 221 | 245 | ||
| @@ -1,6 +1,7 @@ | |||||
| 1 | package browser | 1 | package browser | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | + | "context" | |||
| 4 | "database/sql" | 5 | "database/sql" | ||
| 5 | "embed" | 6 | "embed" | ||
| 6 | "log" | 7 | "log" | ||
| @@ -136,6 +137,12 @@ func (app *BrowserApp) Initialize() error { | |||||
| 136 | app.parserService = services.NewParserService(app.config, app.queries) | 137 | app.parserService = services.NewParserService(app.config, app.queries) | ||
| 137 | app.browserService = services.NewBrowserService(app.config, app.queries) | 138 | app.browserService = services.NewBrowserService(app.config, app.queries) | ||
| 138 | 139 | ||||
| 140 | + | // Load zoom levels into in-memory cache for fast page transitions | |||
| 141 | + | if err := app.browserService.LoadZoomCacheFromDB(context.Background()); err != nil { | |||
| 142 | + | log.Printf("Warning: failed to load zoom cache: %v", err) | |||
| 143 | + | // Non-fatal - zoom will fall back to defaults | |||
| 144 | + | } | |||
| 145 | + | ||||
| 139 | // Initialize handlers | 146 | // Initialize handlers | ||
| 140 | app.schemeHandler = api.NewSchemeHandler(app.assets, app.parserService, app.browserService) | 147 | app.schemeHandler = api.NewSchemeHandler(app.assets, app.parserService, app.browserService) | ||
| 141 | app.messageHandler = messaging.NewHandler(app.parserService, app.browserService) | 148 | app.messageHandler = messaging.NewHandler(app.parserService, app.browserService) | ||
| @@ -211,11 +218,28 @@ func (app *BrowserApp) cleanup() { | |||||
| 211 | app.workspace = nil | 218 | app.workspace = nil | ||
| 212 | } | 219 | } | ||
| 213 | 220 | ||||
| 214 | - | // Close database last | 221 | + | // Flush pending history writes before closing database |
| 222 | + | if app.browserService != nil { | |||
| 223 | + | log.Printf("Flushing pending history writes...") | |||
| 224 | + | app.browserService.FlushHistoryQueue() | |||
| 225 | + | } | |||
| 226 | + | ||||
| 227 | + | // Close database with WAL checkpoint | |||
| 215 | if app.database != nil { | 228 | if app.database != nil { | ||
| 216 | - | log.Printf("Closing database") | 229 | + | log.Printf("Performing WAL checkpoint and closing database...") |
| 230 | + | ||||
| 231 | + | // Run WAL checkpoint to commit all pending writes and truncate WAL file | |||
| 232 | + | if _, err := app.database.Exec("PRAGMA wal_checkpoint(TRUNCATE)"); err != nil { | |||
| 233 | + | log.Printf("Warning: WAL checkpoint failed: %v", err) | |||
| 234 | + | } else { | |||
| 235 | + | log.Printf("WAL checkpoint completed successfully") | |||
| 236 | + | } | |||
| 237 | + | ||||
| 238 | + | // Close database connection | |||
| 217 | if closeErr := app.database.Close(); closeErr != nil { | 239 | if closeErr := app.database.Close(); closeErr != nil { | ||
| 218 | log.Printf("Warning: failed to close database: %v", closeErr) | 240 | log.Printf("Warning: failed to close database: %v", closeErr) | ||
| 241 | + | } else { | |||
| 242 | + | log.Printf("Database closed successfully") | |||
| 219 | } | 243 | } | ||
| 220 | } | 244 | } | ||
| 221 | 245 | ||||