RocksDB Migrations
This guide documents migration behavior in RocksDBDataStore and how to operate it safely.
Preferred API:
- pass migration settings as
migrationConfiguration = MigrationConfiguration(...) - flat migration arguments on
RocksDBDataStore.open(...)still work for compatibility
When migration is required
Section titled “When migration is required”On open, the store compares persisted model definitions with configured models.
No migration required (automatic):
- new model
- safe property additions
- new indexes on compatible existing properties (index backfill)
- relaxed validation
Migration required:
- incompatible property type changes
- removals/renames without alternatives
- stricter validation changes that break compatibility
Handler contract
Section titled “Handler contract”All migration hooks receive MigrationContext<RocksDBDataStore> and return MigrationOutcome:
Success: phase completePartial: progress persisted, continue with provided cursor/messageRetry: retry same phase (optional delay)Fatal: migration fails
Available hooks:
migrationExpandHandlermigrationHandler(Backfill)migrationVerifyHandlermigrationContractHandler
Runtime phases
Section titled “Runtime phases”Runtime phase order:
ExpandBackfillVerifyContract
Progress is persisted per model with MigrationState (phase, status, attempt, cursor, message, version range).
If the process restarts, migration resumes from persisted state.
Current handler hooks:
Expand: runsmigrationExpandHandlerBackfill: runsmigrationHandlerVerify: runsmigrationVerifyHandlerContract: runsmigrationContractHandler
Dependency ordering and cycles
Section titled “Dependency ordering and cycles”Migrations are executed in dependency order across models.
- A model migrates after models it references.
- Cycles are rejected before execution with
MigrationException.
This prevents dependent models from migrating against stale referenced schemas.
Startup handoff to background
Section titled “Startup handoff to background”Use:
migrationConfiguration.migrationStartupBudgetMsmigrationConfiguration.continueMigrationsInBackground = true
Behavior:
- If budget is exceeded, migration continues in background.
- Requests to pending models are blocked until completion.
Operator control API
Section titled “Operator control API”pendingMigrations()migrationStatus(modelId)migrationStatuses()awaitMigration(modelId)pauseMigration(modelId)resumeMigration(modelId)cancelMigration(modelId, reason)
These APIs are intended for operational tooling and rollout control.
cancelMigration is terminal for the current store instance: the model stays blocked and you must reopen the store to resume from persisted state.
Operator semantics:
awaitMigration(modelId)returns normally when migration completes successfully.awaitMigration(modelId)completes exceptionally withMigrationExceptionif migration fails or is canceled.pauseMigration(modelId)only affects pending/background progress. It does not interrupt a currently running phase step.- While paused, the model remains request-blocked.
resumeMigration(modelId)allows the next background loop iteration to continue from the persistedMigrationState.- After
cancelMigration, the current store instance keeps the model blocked. Reopening the store resumes from the persisted phase/cursor.
Lease behavior
Section titled “Lease behavior”Default lease is RocksDBLocalMigrationLease.
- Prevents duplicate runners in-process.
- Cross-process migration lease is usually unnecessary because RocksDB lock already enforces a single opener.
You can inject migrationLease for custom orchestration.
Observability
Section titled “Observability”Retry controls:
migrationConfiguration.migrationRetryPolicy.maxAttemptsmigrationConfiguration.migrationRetryPolicy.maxRetryOutcomes
Status payload includes:
- runtime state
- current phase
- attempt
- last error
- cursor presence
- retry count
- ETA estimate
Metrics:
migrationMetrics(modelId)/migrationMetrics()
Audit events:
- default: emitted to
migrationConfiguration.migrationAuditEventReporter(default reporter logs line output) - optional persistence: set
migrationConfiguration.persistMigrationAuditEvents = true - read persisted history:
migrationAuditEvents(modelId, limit)
Recommended rollout pattern
Section titled “Recommended rollout pattern”- Deploy with
migrationConfiguration.continueMigrationsInBackground = true. - Set conservative retry policy.
- Watch
migrationStatuses()andmigrationMetrics(). - Use
pause/resume/cancelonly for operator interventions. - Enable persisted audit events only when durable per-model history is required.
Minimal four-phase example
Section titled “Minimal four-phase example”RocksDBDataStore.open( keepAllVersions = true, relativePath = "path/to/store", dataModelsById = mapOf(1u to Account), migrationConfiguration = MigrationConfiguration( migrationExpandHandler = { context -> // Prepare compatibility before data rewrite MigrationOutcome.Success }, migrationHandler = { context -> // Backfill existing rows MigrationOutcome.Success }, migrationVerifyHandler = { context -> // Validate rewritten data MigrationOutcome.Success }, migrationContractHandler = { context -> // Final cleanup after verification MigrationOutcome.Success } ))