Skip to content

fix: harden DB reload after Google Drive download (#21)#22

Merged
geokoko merged 5 commits intomasterfrom
fix/drive-db-reload
Mar 14, 2026
Merged

fix: harden DB reload after Google Drive download (#21)#22
geokoko merged 5 commits intomasterfrom
fix/drive-db-reload

Conversation

@geokoko
Copy link
Copy Markdown
Owner

@geokoko geokoko commented Mar 14, 2026

The download-and-reload cycle could leave the app operating against stale H2 connections, causing changes to be lost. Fixes issue #21

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.

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.
@geokoko geokoko self-assigned this Mar 14, 2026
@geokoko geokoko added the bug Something isn't working label Mar 14, 2026
Copilot AI review requested due to automatic review settings March 14, 2026 21:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 DatabaseReloadService shutdown/reconnect flow: drain active Hikari connections after SHUTDOWN, add reconnect retries with explicit connection validation, and verify JdbcTemplate works before running migrations.
  • Add resetAfterReload() hooks to TaskService and StudyService to clear cached “processed today” guards after a reload.
  • Wire the reload listener in StudySyncUI to 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.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 DatabaseReloadService to wait for active connections to drain after SHUTDOWN, and add reconnect validation/retry logic.
  • Add resetAfterReload() hooks to TaskService and StudyService to clear once-per-day processing guards after a DB reload.
  • Wire the reload listener in StudySyncUI to 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.

geokoko added 3 commits March 15, 2026 00:30
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.
@geokoko geokoko merged commit f811da0 into master Mar 14, 2026
1 check passed
@geokoko geokoko deleted the fix/drive-db-reload branch March 14, 2026 22:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants