Files
kandev/docs/plans/large-database-startup/plan.md
T
2026-09-12 16:29:38 +01:00

3.7 KiB

created, status, requirements, system_design, legacy_specs
created status requirements system_design legacy_specs
2026-09-11 complete
REQ-PLATFORM-STARTUP-LIFECYCLE-001
../../specs/platform/system-design/startup-lifecycle.md

Large database startup implementation plan

Root cause

provideRepositories performs the upgrade backup and migrations before startGatewayAndServe binds the bootstrap listener. The reported 42.5-second backup consumes almost all of the 45-second listener budget.

Scope and approach

Move shared bootstrap ownership before initialization. Add typed phase reporting and cancellation-aware backup execution. Preserve version gates, retention, health identity, binding semantics, and background recovery ordering.

Work orders

Verification

Backend commands run from apps/backend; script and diff commands run from root.

  • rtk go test -race ./internal/backendapp ./internal/persistence ./internal/launcher ./internal/common/config ./internal/db
  • rtk go test ./internal/task/repository/sqlite -run 'Test(StartupMigrationCosts|StartupMigrationCostsPopulated|NewWithDBContextStopsActiveMigration|BackfillPromptSeqStopsOnCanceledContext)' -v
  • rtk proxy python3 scripts/lint-spec-files.py --all
  • rtk proxy node --test scripts/validate-public-docs.test.mjs
  • rtk proxy node scripts/validate-public-docs.mjs
  • rtk git diff --check

End-to-end evidence

Use real HTTP listeners with controlled initialization and short launcher health deadlines. Cover success, failure, route isolation, cancellation, and bind failure. No browser UI changes or live database access are needed.

Risks

Legacy constructors include non-context SQL. Shutdown must not race cleanup with those constructors. Retry retention can discard the original snapshot; no reuse or retention changes are authorized in this package.

Results

Implemented early bootstrap ownership, typed startup phases, cancellation-aware SQLite backup and task migration execution, worker-only restore quiescing, launcher phase diagnostics, populated startup measurements, and public troubleshooting documentation.

Validation passed:

  • env -u KANDEV_INTERNAL_CONFIG_FILE -u KANDEV_INTERNAL_CONFIG_HOME_FILE -u KANDEV_INTERNAL_AGENTCTL_STARTUP_CONFIG -u KANDEV_HEALTH_TIMEOUT_MS go test -race ./internal/backendapp ./internal/persistence ./internal/launcher ./internal/common/config ./internal/db -count=1
  • go test -race ./internal/startup -count=1
  • go test -race ./internal/persistence/storeconformance -count=1
  • go test ./internal/task/repository/sqlite -run 'Test(StartupMigrationCosts|StartupMigrationCostsPopulated|NewWithDBContextStopsActiveMigration|BackfillPromptSeqStopsOnCanceledContext)$' -v -count=1
  • make -C apps/backend build
  • make -C apps/backend lint (0 issues)
  • go run ./cmd/sqlguard ./internal
  • python3 scripts/lint-spec-files.py --all
  • node --test scripts/validate-public-docs.test.mjs (62 passed)
  • node scripts/validate-public-docs.mjs (46 published pages)
  • git diff --check

The populated isolated SQLite evidence is recorded in task-02-evidence. It covers a 929,792-byte database, 6,000 messages, a 2,252,800-byte VACUUM INTO snapshot, 285.06 ms replay, and separate recurring backfill timings on Linux amd64 with Go 1.26.0. The measurement remains synthetic and does not predict production startup time.

Deferred risks remain outside this package: backup retry retention and the backup-registry redesign are unchanged. Constructors for non-task stores still have bounded admission barriers rather than a new shared context API; an already admitted statement can finish according to its driver's cancellation behavior before the next store is rejected.