fix(launcher): guard orphan bake publication
This commit is contained in:
parent
3f68895120
commit
208a70ac83
14 changed files with 829 additions and 55 deletions
|
|
@ -120,10 +120,9 @@ public sealed class LauncherInstaller : ILauncherInstaller
|
|||
_recordStore.DataDirectory,
|
||||
cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
BakeOutputStagingContract.DeleteOwnedStagingFiles(
|
||||
_recordStore.PreparedAssetPath);
|
||||
InstallRecordVerification verification = await _recordStore
|
||||
.LoadAndVerifyUnderLeaseAsync(cancellationToken)
|
||||
InstallRecordVerification verification =
|
||||
await RecoverExistingUnderPublicationGuardAsync(
|
||||
cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
_verifiedRecord = verification.Record;
|
||||
return verification;
|
||||
|
|
@ -197,9 +196,8 @@ public sealed class LauncherInstaller : ILauncherInstaller
|
|||
|
||||
string outputPath = _recordStore.PreparedAssetPath;
|
||||
string backupPath = LauncherInstallRecordStore.GetBackupPath(outputPath);
|
||||
BakeOutputStagingContract.DeleteOwnedStagingFiles(outputPath);
|
||||
InstallRecordVerification existing = await _recordStore
|
||||
.LoadAndVerifyUnderLeaseAsync(cancellationToken)
|
||||
InstallRecordVerification existing =
|
||||
await RecoverExistingUnderPublicationGuardAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
_verifiedRecord = existing.Record;
|
||||
|
||||
|
|
@ -220,6 +218,7 @@ public sealed class LauncherInstaller : ILauncherInstaller
|
|||
|
||||
var parser = new BakeProgressJsonlParser();
|
||||
var protocol = new BakeProgressProtocol();
|
||||
string? publicationNonce = null;
|
||||
|
||||
void Observe(BakeProgressEvent progressEvent)
|
||||
{
|
||||
|
|
@ -265,11 +264,26 @@ public sealed class LauncherInstaller : ILauncherInstaller
|
|||
try
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
publicationNonce = BakePublicationGuardPaths.CreateNonce();
|
||||
await using (
|
||||
BakePublicationGuardContract.PublicationLease publication =
|
||||
await BakePublicationGuardContract.AcquireAsync(
|
||||
outputPath,
|
||||
cancellationToken)
|
||||
.ConfigureAwait(false))
|
||||
{
|
||||
BakePublicationGuardContract.Authorize(
|
||||
outputPath,
|
||||
publicationNonce,
|
||||
publication);
|
||||
}
|
||||
|
||||
var request = new BakeProcessRequest(
|
||||
_bakeExecutablePath,
|
||||
validation.Directory,
|
||||
outputPath,
|
||||
threads);
|
||||
threads,
|
||||
publicationNonce);
|
||||
BakeProcessResult processResult = await _processRunner.RunAsync(
|
||||
request,
|
||||
chunk =>
|
||||
|
|
@ -370,7 +384,11 @@ public sealed class LauncherInstaller : ILauncherInstaller
|
|||
.ConfigureAwait(false);
|
||||
|
||||
_verifiedRecord = record;
|
||||
LauncherInstallRecordStore.TryDelete(backupPath);
|
||||
await FinalizeSuccessfulPublicationAsync(
|
||||
outputPath,
|
||||
backupPath,
|
||||
publicationNonce)
|
||||
.ConfigureAwait(false);
|
||||
Report(
|
||||
progress,
|
||||
LauncherInstallPhase.Completed,
|
||||
|
|
@ -381,7 +399,12 @@ public sealed class LauncherInstaller : ILauncherInstaller
|
|||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
RestorePreviousPackage(outputPath, backupPath, previousPreserved);
|
||||
await FinalizeFailedPublicationAsync(
|
||||
outputPath,
|
||||
backupPath,
|
||||
previousPreserved,
|
||||
publicationNonce)
|
||||
.ConfigureAwait(false);
|
||||
Report(
|
||||
progress,
|
||||
LauncherInstallPhase.Cancelled,
|
||||
|
|
@ -390,7 +413,12 @@ public sealed class LauncherInstaller : ILauncherInstaller
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
RestorePreviousPackage(outputPath, backupPath, previousPreserved);
|
||||
await FinalizeFailedPublicationAsync(
|
||||
outputPath,
|
||||
backupPath,
|
||||
previousPreserved,
|
||||
publicationNonce)
|
||||
.ConfigureAwait(false);
|
||||
Report(
|
||||
progress,
|
||||
LauncherInstallPhase.Failed,
|
||||
|
|
@ -402,10 +430,62 @@ public sealed class LauncherInstaller : ILauncherInstaller
|
|||
|
||||
throw new LauncherInstallException("Installation failed.", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BakeOutputStagingContract.DeleteOwnedStagingFiles(outputPath);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<InstallRecordVerification>
|
||||
RecoverExistingUnderPublicationGuardAsync(
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
string outputPath = _recordStore.PreparedAssetPath;
|
||||
await using BakePublicationGuardContract.PublicationLease publication =
|
||||
await BakePublicationGuardContract.AcquireAsync(
|
||||
outputPath,
|
||||
cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
// Any child whose parent died before it acquired this lock is now
|
||||
// irrevocably stale. A child already holding the lock must finish its
|
||||
// promotion before recovery reaches this invalidation point.
|
||||
BakePublicationGuardContract.Invalidate(outputPath, publication);
|
||||
BakeOutputStagingContract.DeleteOwnedStagingFiles(outputPath);
|
||||
return await _recordStore.LoadAndVerifyUnderLeaseAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task FinalizeSuccessfulPublicationAsync(
|
||||
string outputPath,
|
||||
string backupPath,
|
||||
string publicationNonce)
|
||||
{
|
||||
await using BakePublicationGuardContract.PublicationLease publication =
|
||||
await BakePublicationGuardContract.AcquireAsync(
|
||||
outputPath,
|
||||
CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
BakePublicationGuardContract.Invalidate(
|
||||
outputPath,
|
||||
publication,
|
||||
publicationNonce);
|
||||
LauncherInstallRecordStore.TryDelete(backupPath);
|
||||
BakeOutputStagingContract.DeleteOwnedStagingFiles(outputPath);
|
||||
}
|
||||
|
||||
private static async Task FinalizeFailedPublicationAsync(
|
||||
string outputPath,
|
||||
string backupPath,
|
||||
bool previousPreserved,
|
||||
string? publicationNonce)
|
||||
{
|
||||
await using BakePublicationGuardContract.PublicationLease publication =
|
||||
await BakePublicationGuardContract.AcquireAsync(
|
||||
outputPath,
|
||||
CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
BakePublicationGuardContract.Invalidate(
|
||||
outputPath,
|
||||
publication,
|
||||
publicationNonce);
|
||||
RestorePreviousPackage(outputPath, backupPath, previousPreserved);
|
||||
BakeOutputStagingContract.DeleteOwnedStagingFiles(outputPath);
|
||||
}
|
||||
|
||||
private bool PreservePreviousPackage(string outputPath, string backupPath)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue