Skip to content

v1.7.1

Choose a tag to compare

@jakemorgangit jakemorgangit released this 17 Aug 20:09
· 11 commits to main since this release
832e847

Two new capabilities and two fixes since v1.7.0. No breaking changes, no config or schema changes — upgrading is a straight swap of the exe.

The one worth upgrading for

A completed restore could surface as a crash. Reading the console to file a run's receipt was not thread-safe: the line collection could be enumerated while another thread was still appending to it, handing back a null and throwing. That happened inside the run's own finally block, unguarded, so it came out of the restore itself — the database restored, the target online, and an exception on screen.

It was found as a red build rather than by looking for it, which is the only reason it was found at all: it needs a particular interleaving, so it would have shown up on somebody's machine occasionally and never reproduced when they went looking.

The console now snapshots before reading and tolerates a torn one, and filing a receipt can no longer fail the thing it is filing — if the history cannot be written, it says so on the console and the restore stands.

Copy a database for a cutover, not just a refresh

A copy brought the target online. That is right for refreshing a test environment and wrong for a migration: online means no more log backups can be applied, so the copy is frozen at the moment it was taken, and the downtime is however long the full takes.

There is now an option to leave the target in RESTORING instead. With it ticked, the source can be asked which log backups it has taken since the copy — and where they went — with the statements to apply them. The long part happens in advance and the switch-over costs only the tail.

Off by default, because a database left in RESTORING is not usable and somebody refreshing a test environment wants the opposite. The screen says which it will be.

Both service accounts are proven against the shared folder, before the backup

The Copy screen has always said it: the source writes there as its own service account and the target reads there as its own — two different accounts, and routinely not the same one. What it also said, accurately, was that the target's read is checked after the backup, because the check ran on a file and there is no file until the backup has been written.

So a share the target could not read cost you the whole backup first. On a large database that is a long wait to be told something knowable in a second. The source's write was never checked ahead of time at all — it was discovered by the backup failing.

Both are now asked as themselves when the scripts are generated, before anything is written. The two verdicts are kept apart, because the fix for either is a permission grant to a specific account and one combined answer loses which one. It stays honest about what it proves: the folder is reachable by that account, not that a backup inside it will open — a share can be traversable and still refuse the read — so the file-level check after the backup remains the authoritative one.

The gap check can be found

The "what is this container missing" check shipped in 1.7.0 inside the restore options — behind a step you only reach after confirming a restore point computed from the very chain it exists to question. A feature whose whole point is telling you the chain is shorter than you think cannot require you to already suspect that.

It now sits in Select source, beside Audit these backups, reachable as soon as a database is picked.


Downloads. NineLives.exe is the app, 9lives.exe the CLI; take the -arm64 builds on Windows on ARM. Both are single self-contained executables — no installation. The zips carry both front ends together.

The binaries are unsigned, so SmartScreen will warn on first run (#33); each release carries a build provenance attestation you can verify with gh attestation verify.

Full detail in CHANGELOG.md.