Skip to content

[IN PROGRESS] Migration engine for the primary instance - #5894

Draft
warwickschroeder wants to merge 16 commits into
masterfrom
warwick/migration-engine-1
Draft

warwickschroeder wants to merge 16 commits into
masterfrom
warwick/migration-engine-1

Conversation

@warwickschroeder

@warwickschroeder warwickschroeder commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

What this adds

The migration engine moves an error instance's data from RavenDB to SQL Server or PostgreSQL. ServiceControl copies the data it needs while it is closed, opens on SQL, then copies the rest in the background. This is the base branch for the whole engine. It is not finished, and a real instance with Migration/Enabled turned on still refuses to copy anything until the last milestone below.

Architecture

The engine core knows nothing about RavenDB or SQL, so it can easily be extended in future to copy between any two persisters:

  • The engine sits in the middle. MigrationEngine handles batching, resuming, failures and progress, and only talks to a source and a target.
  • A source reads. It implements IMigrationSource, with one reader per kind of data. Today that is RavenDB.
  • A target writes. It implements IMigrationTarget and IMigrationCheckpointStore, with one writer per kind of data. Today that is the shared EF Core target, which covers SQL Server and PostgreSQL.
  • Adding a new pair takes a source or target for the new persister, a reader or writer for each kind of data, and a change to MigrationPairIsSupportedCheck, which is the one place that says RavenDB to SQL is the only pair allowed today.

Target State

  • Is predictable. A dry run shows what will move and roughly how long ServiceControl will be closed.
  • Is one setting. Turn on Migration/Enabled and start ServiceControl as usual.
  • Never changes RavenDB. It only reads from it.
  • Survives a stop at any point without losing or doubling a row, because each batch saves its rows and its progress together.
  • Never decides on its own when something fails. A failed part waits to be retried or given up, so a restart cannot loop or lose data.
  • Is visible while it runs, through ServicePulse, the log and read-only status and verify commands.
  • Can be undone for free, right up until ServiceControl first opens on SQL.

The docs describe the target state in full:

  • Overview: what moves, what is skipped, and what happens when something goes wrong.
  • Instructions: how an operator runs the migration, step by step.
  • System design: which class does what, and the order things run in.

Milestones

Each milestone lands on this branch as its own PR, stacked here and reviewed on its own. This branch goes to master once the last one is in.

  • Foundation ([IN PROGRESS] Migration engine for the primary instance #5894): a safe, read-only way to open and count the old RavenDB data, and the copy engine tested against fakes.
  • Saving progress ([Migration Engine Part 2] Add a migration checkpoint table to SQL Server and PostgreSQL #5897): a progress table on SQL Server and PostgreSQL, so a stopped copy resumes instead of starting over.
  • Copying at startup ([Migration Engine Part 3] Implement the RavenDB to SQL migration machinery #5911): the engine wired into ServiceControl, the startup checks, the Done, Failed and Abandoned rules, and the first two parts of the data.
  • Failed messages and their bodies (Copy unresolved failed messages and their bodies to SQL #6005): unresolved failed messages come across with their message bodies, which is usually the biggest part of the outage.
  • The rest of the required data: throughput and licensing data, redirects, subscriptions, retry history, notification settings, custom checks, pending integration events and group comments.
  • Copying in the background: once ServiceControl is open, the event log and archived and resolved messages copy quietly behind it.
  • Finishing safely: --migration-retry and --migration-abandon, and a guard that stops the migration being switched off with anything unfinished.
  • Seeing what is happening: progress in the ServicePulse activity feed, --migration-status, --migration-verify and the dry run.
  • Ready to ship: embedded, container and cloud-hosted RavenDB all supported, the customer docs finished, and the lock that stops a real copy removed.

Tests

  • ServiceControl.UnitTests/Migration: the engine, its halt and resume rules, each startup check and the refusal messages, against fakes and a fake clock.
  • ServiceControl.Persistence.Tests/EFCore: the progress table, the target and its writers, on SQL Server and PostgreSQL.
  • ServiceControl.Persistence.Tests.RavenDB/DataMigration: the read-only source and its readers against an embedded server.
  • ServiceControl.Persistence.Tests.SqlServer: endpoint settings keys that differ only in letter case.
  • ServiceControl.Migration.Tests (new): the source report, both persisters in one process, and every reader having a matching writer.
  • ServiceControl.Migration.AcceptanceTests (new): a killed copy, a restart, each refusal and ServiceControl opening on SQL, on both providers.

@rbev rbev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Partial review - adding as comments for now.

Comment thread docs/migration/ravendb-to-sql-migration-instructions.md Outdated
Comment thread docs/migration/ravendb-to-sql-migration-overview.md Outdated
Comment thread docs/migration/ravendb-to-sql-migration-overview.md Outdated
Comment thread docs/migration/ravendb-to-sql-migration-overview.md Outdated
Comment thread src/ServiceControl.Persistence/DataMigration/IMigrationTarget.cs Outdated
Comment thread src/ServiceControl.Persistence/DataMigration/IMigrationTarget.cs Outdated
Comment thread src/ServiceControl.Persistence/DataMigration/MigrationEngine.cs Outdated
Comment thread src/ServiceControl.Persistence/DataMigration/MigrationEngine.cs
@warwickschroeder
warwickschroeder added this pull request to stack #5898 September 16, 2026 04:25
@warwickschroeder warwickschroeder changed the title Implement the foundation for migration engine [Migration Engine Part 2] Implement the foundation for migration engine Sep 16, 2026
@warwickschroeder warwickschroeder changed the title [Migration Engine Part 2] Implement the foundation for migration engine [Migration Engine Part 1] Implement the foundation for migration engine Sep 16, 2026
Comment thread src/ServiceControl.UnitTests/Migration/MigrationEngineCategorySelectionTests.cs Outdated
Comment thread src/ServiceControl.UnitTests/Migration/MigrationEngineCategorySelectionTests.cs Outdated

@johnsimons johnsimons left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A few question and comments but overall, lets keep going

Comment thread docs/migration/ravendb-to-sql-migration-instructions.md Outdated
Comment thread docs/migration/ravendb-to-sql-migration-overview.md Outdated
Comment thread docs/migration/ravendb-to-sql-migration-overview.md Outdated
Comment thread docs/migration/ravendb-to-sql-migration-overview.md Outdated
Comment thread docs/migration/ravendb-to-sql-migration-overview.md Outdated
Comment thread docs/migration/ravendb-to-sql-migration-overview.md Outdated
Comment thread docs/migration/ravendb-to-sql-migration-overview.md Outdated
Comment thread docs/migration/ravendb-to-sql-migration-overview.md Outdated
Comment thread docs/migration/ravendb-to-sql-migration-overview.md Outdated
…n, clarifying strategies, goals, and migration limitations.
…on source reporting

- Implemented MigrationEngineFailurePathTests to validate behavior during write failures and halts.
- Created MigrationEngineHaltTests to ensure categories halt correctly on systemic failures.
- Added MigrationEngineOptionsTests to verify default and environment variable configurations.
- Developed MigrationEngineOrderingTests to check execution order of migration categories.
- Introduced MigrationEngineResumeTests to confirm no duplicates or gaps after restarts.
- Added MigrationEngineRunCategoriesTests to ensure all categories run in specified order.
- Implemented MigrationEngineSkipReasonTests to validate skip reasons and their aggregation.
- Enhanced MigrationEngineThrottleTests to verify pause behavior for optional categories.
- Updated MigrationSourceReportCommand for improved output and clarity.
- Modified Help.txt and HostArguments.cs for better command descriptions.
- Refined Settings.cs and PersistenceFactory.cs for clearer migration source configuration.
- Introduced `BenignSkipped` property in `MigrationWriteResult` to track rows that the target would have deleted anyway.
- Updated `MigrationEngine` logic to ensure benign skips do not count towards the halt threshold.
- Added tests to verify that benign skips are handled correctly and do not cause category halts.
- Updated skip reasons to include `PastRetention` for better clarity on skipped rows.
- Created approval files for category selection tests to ensure correct order and configuration.
- Improved error logging in MigrationEngine to provide clearer context on exceptions.
- Added functionality to InMemoryMigrationSource to simulate shutdown behavior during body reads.
- Enhanced InMemoryMigrationTarget to allow custom exceptions for failure scenarios.
- Introduced TimerRecordingTimeProvider to facilitate testing of timer-related functionality.
- Expanded HaltThresholdTests to cover edge cases involving mixed benign and fault skips.
- Updated MigrationEngineBodyRetryTests to ensure proper handling of shutdowns during body reads.
- Added tests to verify behavior when categories are empty or already completed.
- Implemented checks for checkpoint conflicts and cancellation scenarios in MigrationEngineFailurePathTests.
- Enhanced MigrationEngineHaltTests to evaluate mixed skip scenarios and their impact on halting.
- Improved MigrationEngineOrderingTests to ensure blocked categories behave correctly.
- Added tests to MigrationEngineResumeTests to verify that restart behavior maintains original start time.
- Updated MigrationEngineRunCategoriesTests to handle cases where no categories are selected.
- Enhanced MigrationEngineSkipReasonTests to ensure accurate recording of multiple skip reasons.
- Added tests to MigrationEngineThrottleTests to verify behavior during pauses and shutdowns.
@warwickschroeder
warwickschroeder force-pushed the warwick/migration-engine-1 branch from 8949344 to 0dcf9c8 Compare September 30, 2026 01:24
@warwickschroeder
warwickschroeder removed this pull request from stack #5898 October 9, 2026 01:45
…ver and PostgreSQL (#5897)

* feat: Add Migration Checkpoints to EF Core

- Introduced a new table `MigrationCheckpoints` to track migration states and progress.
- Implemented `MigrationCheckpointEntity` to represent the checkpoint data structure.
- Added `EFMigrationCheckpointStore` for managing checkpoint data with methods for reading and upserting checkpoints.
- Created `MigrationCheckpointConfiguration` for configuring the entity in the DbContext.
- Enhanced `ServiceControlDbContext` to include the new `MigrationCheckpoints` DbSet.
- Updated `EfCoreExtensions` to provide an `UpsertCheckpoint` method for managing checkpoint persistence.
- Added unit tests for `EFMigrationCheckpointStore` and `MigrationCheckpointTable` to ensure correct functionality.
- Implemented transaction handling in `MigrationCheckpointTransactionTests` to verify checkpoint behavior during commits and rollbacks.
- Updated RavenDB integration to support embedded server readiness checks.

* feat: Enhance migration engine with improved error handling and configuration options

* feat: Refactor migration checkpoint handling and add UpsertCheckpoint method

* docs: Update migration documentation for clarity on RavenDB to SQL migration process

* [Migration Engine Part 3] Implement the RavenDB to SQL migration machinery (#5911)

* Update migration documentation

* feat: run the required migration copy at host start

Adds the RavenDB source and the EF Core target for the KnownEndpoints and EndpointSettings categories, the startup checks that refuse an unsupported or unready migration, and the stall watchdog that stops a copy committing nothing for 30 minutes. Documents the migration contracts.

* test: cover the RavenDB to SQL migration end to end

Adds unit tests for the startup checks, the stall watchdog and the refusals, target and reader tests for both persisters, a SQL Server collation test for the endpoint settings key, and acceptance tests for a copy that is killed, restarted and opened on. Approves the two new migration settings.

* tests: ensure DB schema is setup before the host starts

* refactor: update BatchSizeFor method to return Task<int> for async compatibility across migration targets

* docs: update migration instructions and system design to clarify settings and behavior

* Refactor migration checks and improve error handling

* Refactor migration commands and error handling

* PR review

* Fix flakey test
@warwickschroeder warwickschroeder changed the title [Migration Engine Part 1] Implement the foundation for migration engine [IN PROGRESS] Migration engine for the primary instance Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants