Reaper 4.2 moves local repair state into SQLite
Reaper 4.2 replaces EclipseStore in its local storage backend and adds a schedule-aware repair metric. The implementation changes what operators should verify during an upgrade.
Reaper 4.2.0, released on January 30, replaces EclipseStore in its in-memory storage backend with SQLite. That description needs some qualification. The backend retains its memory-oriented name, but its implementation supports both a volatile database and a persistent database file. For an operator, the important question is which mode the running process selects and what happens to existing repair state during the transition.
I am interested in Cassandra because it addresses demanding active-active requirements. My enthusiasm comes with a preference for using it only where those requirements justify the operational work. Repair tooling belongs in that assessment. A change to the storage behind a repair orchestrator deserves examination even when the database being repaired has not changed.
The companion change in this release concerns evidence that scheduled work completes. Reaper adds an unfulfilled repair schedule metric that accounts for the configured interval. Together, the changes make this a useful release to examine through the relationship between recorded work and overdue work.
What the storage replacement changes
The storage migration proposal describes a replacement of EclipseStore with a relational SQLite database. It introduces database access implementations for repair state and an automatic migration of existing EclipseStore data. The proposal also identifies concurrent access to prepared statements as an implementation concern. Its synchronization changes address result-set errors during background activity.
The tagged MemoryStorageFacade implementation gives a more precise account of the storage modes. An absent or empty persistence path creates an in-memory SQLite connection. A supplied path represents a directory, and Reaper opens a file called reaper.db inside it. It creates the directory if necessary. The code explicitly logs that the volatile mode loses data on restart.
Those branches matter more than the class name. An operator who sees SQLite in the release announcement should not infer that every deployment now persists its state. The configured path still determines whether the database survives a process restart. I would verify the startup log and the actual storage directory as part of an upgrade check. In a container deployment, I would also verify that the chosen directory has the intended lifetime.
The same constructor enables autocommit, initializes the schema, and then checks for legacy data when persistence is enabled. Only after those steps does it construct the data access objects. This ordering means that the migration is part of storage initialization. It is not a separate administrative action that can be postponed while the new process starts normal work.
For me, the attraction of a relational representation here is the ability to inspect the recorded entities without reconstructing an object graph. The proposal describes tables for repair runs, segments and schedules, among other entities. That is useful operationally, but I would still treat direct inspection as diagnosis. Editing the database behind a running orchestrator would require understanding its application invariants and concurrent activity.
The automatic migration has an upgrade boundary
The tagged EclipseStore migration implementation detects legacy storage by looking for directory entries whose names begin with channel_. It loads the old storage root and transfers its collections into SQLite. After that transfer succeeds, it invokes the routine that backs up the EclipseStore files.
That sequence gives an operator several concrete things to verify. The new process must receive the directory containing the existing state. Its logs should identify legacy data and report the migration result. The resulting database should contain the expected clusters and schedules. An apparently successful startup against an empty directory would not demonstrate that the old state had been transferred.
There is also a transaction detail worth reading before writing a rollback procedure. The migration code performs its work with the connection already in autocommit mode. It does not wrap the complete transfer in one explicit transaction. Its insertion routines use INSERT OR REPLACE statements. I would therefore avoid describing the whole conversion as an atomic operation. A failure partway through needs investigation against both the original files and the partially populated destination.
My preference would be to retain a separate copy of the original storage directory before the first upgraded start. I would rehearse the conversion against a copy and compare the recorded schedules and repair runs. Those are proposed checks, not a claim that I have performed this upgrade. Automatic conversion reduces manual work, but it does not supply evidence that a particular installation's history transferred correctly.
The schema initialization code also records a schema version and runs the initial schema resource when no version exists. This gives the SQLite representation its own upgrade mechanism. A deployment procedure should preserve the database as application state, including its schema metadata.
Measuring a missed repair interval
The new metric addresses a different source of uncertainty. The metric proposal explains that the existing millisSinceLastRepair measurement does not account for the repair schedule's interval. Elapsed time alone cannot express whether a schedule has met its own expected cycle.
The added metric is named io_cassandrareaper_service_RepairScheduleService_unfulfilledRepairSchedule. The proposal defines a value of one when a repair has not completed within the configured interval, and zero when the last repair completed within that cycle. It also checks whether a repair has failed to start after a tolerance of ten percent beyond its planned activation time. The author identifies an earlier run still executing at the next activation as one reason that condition can occur.
This is useful because a schedule can remain configured while its work falls behind. A process-health check would not answer that question. I would use the new value to identify schedules that need investigation, then inspect the corresponding run and its progress. The value describes a scheduling outcome. It does not establish the cause of the delay or justify changing repair concurrency without further evidence.
Paused schedules receive explicit treatment. The proposal says they do not trigger the overdue indication while paused. Resuming a schedule that has remained paused longer than its cycle can set the metric to one. That behavior should inform maintenance procedures and alert interpretation. An overdue indication after a deliberate long pause can be expected, while the subsequent repair still needs to complete.
I would include pause and resume behavior in acceptance checks for the monitoring change. The same check should cover an interval that completes successfully and one that misses its expected activation. The useful evidence after this upgrade is that the intended state survived conversion and that monitoring distinguishes a completed repair cycle from a schedule that has fallen behind.