fix: harden DB reload after Google Drive download (#21)#22
Conversation
The download-and-reload cycle could leave the app operating against stale H2 connections, causing changes to be lost. DatabaseReloadService changes: - shutdown(): after SHUTDOWN and softEvictConnections, poll HikariPoolMXBean.getActiveConnections() until all active connections drain (up to 3s timeout) before returning. - reconnect(): retry up to 5 times with 500ms delays, explicitly validate each connection via Connection.isValid(), and re-evict stale connections between retries. Final SELECT 1 verification ensures JdbcTemplate works before migrations run. Service cache resets: - Add resetAfterReload() to TaskService (clears lastDelayedTasksProcessedDate) and StudyService (clears lastDelayProcessingDate) so once-per-day delay processing re-runs against the freshly loaded database. StudySyncUI wiring: - The reload listener now calls resetAfterReload() on both services before refreshing panels.
There was a problem hiding this comment.
Pull request overview
Hardens the Google Drive “download → replace DB file → reload” workflow to reduce the chance of continuing to operate on stale H2/Hikari connections, and ensures “once-per-day” delay processing re-runs after a live DB swap.
Changes:
- Improve
DatabaseReloadServiceshutdown/reconnect flow: drain active Hikari connections afterSHUTDOWN, add reconnect retries with explicit connection validation, and verifyJdbcTemplateworks before running migrations. - Add
resetAfterReload()hooks toTaskServiceandStudyServiceto clear cached “processed today” guards after a reload. - Wire the reload listener in
StudySyncUIto reset caches before refreshing panels.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/main/java/com/studysync/presentation/ui/StudySyncUI.java | Calls service reset hooks after Drive reload, then refreshes UI panels. |
| src/main/java/com/studysync/domain/service/TaskService.java | Adds a post-reload cache reset method for once-per-day task delay processing. |
| src/main/java/com/studysync/domain/service/StudyService.java | Adds a post-reload cache reset method for once-per-day delayed-goal processing. |
| src/main/java/com/studysync/config/DatabaseReloadService.java | Waits for active connections to drain after shutdown; retries reconnect + validates connectivity before migrations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…rror logging Add @transactional(propagation = NOT_SUPPORTED) to resetAfterReload() in both TaskService and StudyService so the purely in-memory cache reset does not acquire a DB connection from the pool. In DatabaseReloadService.reconnect(), attach the retry-phase exception as suppressed on the final SELECT 1 failure so both the root cause and the verification failure are visible in logs.
There was a problem hiding this comment.
Pull request overview
Hardens the Google Drive database download/reload workflow to reduce the chance of the app continuing to operate on stale H2/Hikari connections, and ensures once-per-day delay processing re-runs after a live DB swap.
Changes:
- Update
DatabaseReloadServiceto wait for active connections to drain afterSHUTDOWN, and add reconnect validation/retry logic. - Add
resetAfterReload()hooks toTaskServiceandStudyServiceto clear once-per-day processing guards after a DB reload. - Wire the reload listener in
StudySyncUIto reset service caches before refreshing the UI.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/main/java/com/studysync/config/DatabaseReloadService.java |
Adds drain-wait on shutdown and reconnect retry/validation to mitigate stale pooled connections post-reload. |
src/main/java/com/studysync/domain/service/TaskService.java |
Adds resetAfterReload() to clear the “mark delayed tasks once/day” guard after DB reload. |
src/main/java/com/studysync/domain/service/StudyService.java |
Adds resetAfterReload() to clear the “process delayed goals once/day” guard after DB reload. |
src/main/java/com/studysync/presentation/ui/StudySyncUI.java |
Calls the new reset hooks on reload before refreshing panels. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
8 tests covering the shutdown-replace-reconnect cycle: - shutdown releases the file lock - shutdown then reconnect restores same data - reload picks up a replacement database file - reload picks up replacement with different row count - reloadDatabase convenience method works - reconnect succeeds without file replacement - multiple shutdown/reconnect cycles are stable - writes after reload persist correctly Uses @tempdir with file-based H2 (not in-memory) to mirror the real Google Drive download flow.
shutdown(): log differently based on drain result — warn with remaining count if connections didn't fully drain, confirm 'all connections drained' on success. reconnect(): attach lastException as suppressed on the interrupt RuntimeException so retry context is preserved in the stack trace.
JaCoCo 0.8.8 fails with 'Unsupported class file major version 65' on Java 21. Version 0.8.11 supports Java 21 class files.
The download-and-reload cycle could leave the app operating against stale H2 connections, causing changes to be lost. Fixes issue #21
DatabaseReloadService changes:
Service cache resets:
StudySyncUI wiring: