diff --git a/docs/designs/PowerShell-AzF-Overall-Design.md b/docs/designs/PowerShell-AzF-Overall-Design.md index 9162d7bb..ed238106 100644 --- a/docs/designs/PowerShell-AzF-Overall-Design.md +++ b/docs/designs/PowerShell-AzF-Overall-Design.md @@ -492,7 +492,7 @@ A snapshot is considered _acceptable_ if it contains any version _allowed_ by th However, if the latest snapshot is _not acceptable_ (i.e. it does not contain module versions required by the manifest), the worker starts installing the dependencies into a new snapshot, and all the subsequent function invocation requests are blocked, waiting for the new snapshot installation to complete. -When a snapshot installation starts, the dependencies are first installed into a folder with a name following a special pattern (`*.i`), so that this snapshot is not picked up by any worker prematurely, before the installation is complete. After _successful_ completion, the snapshot is _atomically promoted_ by renaming the folder to follow a different pattern (`*.r`), which indicates to other workers that this snapshot is ready to use. If the installation fails or cannot complete for any reason (for example, the worker restarts, crashes, or gets decommissioned), the folder stays in the installing state until removed. +When a snapshot installation starts, the dependencies are first installed into a folder with a name following a special pattern (`*i`), so that this snapshot is not picked up by any worker prematurely, before the installation is complete. After _successful_ completion, the snapshot is _atomically promoted_ by renaming the folder to follow a different pattern (`*r`), which indicates to other workers that this snapshot is ready to use. If the installation fails or cannot complete for any reason (for example, the worker restarts, crashes, or gets decommissioned), the folder stays in the installing state until removed. Incomplete and old snapshots that are no longer in use are periodically removed from the file storage. In order to allow detecting unused snapshots, each PowerShell worker keeps "touching" a file named `.used` at the root of the used snapshot folder every `PSWorkerHeartbeatPeriodMinutes` minutes. Before and after installing any new snapshot, every PowerShell worker looks for unused snapshots by checking the folder creation time and the `.used` file modification time. If both these time values are older than (`PSWorkerHeartbeatPeriodMinutes` + `PSWorkerOldSnapshotHeartbeatMarginMinutes`) minutes, the snapshot is considered unused, so the PowerShell worker removes it. The latest `PSWorkerMinNumberOfSnapshotsToKeep` snapshots will never be removed, regardless of usage. (`PSWorkerHeartbeatPeriodMinutes`, `PSWorkerOldSnapshotHeartbeatMarginMinutes`, and `PSWorkerMinNumberOfSnapshotsToKeep` are environment variables configurable via Application Settings of a Function App.) diff --git a/src/DependencyManagement/DependencySnapshotFolderNameTools.cs b/src/DependencyManagement/DependencySnapshotFolderNameTools.cs index 62b1a510..163e4941 100644 --- a/src/DependencyManagement/DependencySnapshotFolderNameTools.cs +++ b/src/DependencyManagement/DependencySnapshotFolderNameTools.cs @@ -10,9 +10,9 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.DependencyManagement internal static class DependencySnapshotFolderNameTools { - private const string InstallingPostfix = ".i"; + private const string InstallingPostfix = "i"; - public const string InstalledPostfix = ".r"; + public const string InstalledPostfix = "r"; public const string InstalledPattern = "*" + InstalledPostfix; @@ -20,7 +20,7 @@ internal static class DependencySnapshotFolderNameTools public static string CreateUniqueName() { - var uniqueBase = DateTime.UtcNow.ToString("yyyyMMdd-HHmmss.ffffff"); + var uniqueBase = DateTime.UtcNow.ToString("yyMMddHHmmssfff"); return uniqueBase + InstalledPostfix; } @@ -29,11 +29,11 @@ public static string CreateUniqueName() /// appending a postfix, so that that the resulting path follows a different /// pattern and can be discovered using a different file mask. /// For example, for the _installed_ path - /// ".../20190710-1234.567890.r" + /// ".../1907101234567r" /// the _installing_ path will be: - /// ".../20190710-1234.567890.r.i" - /// This makes it possible to enumerate all the installed snapshots by using ".../*.r" mask, - /// and all the installing snapshots by using ".../*.i" mask. + /// ".../1907101234567ri" + /// This makes it possible to enumerate all the installed snapshots by using ".../*r" mask, + /// and all the installing snapshots by using ".../*i" mask. /// public static string ConvertInstalledToInstalling(string installedPath) { diff --git a/test/Unit/DependencyManagement/DependencySnapshotFolderNameToolsTests.cs b/test/Unit/DependencyManagement/DependencySnapshotFolderNameToolsTests.cs index c274b3ec..7f997c40 100644 --- a/test/Unit/DependencyManagement/DependencySnapshotFolderNameToolsTests.cs +++ b/test/Unit/DependencyManagement/DependencySnapshotFolderNameToolsTests.cs @@ -17,7 +17,7 @@ public class DependencySnapshotFolderNameToolsTests public void CreatesUniqueEnoughNames() { var name1 = DependencySnapshotFolderNameTools.CreateUniqueName(); - Thread.Sleep(1); // A snapshot name created 1 millisecond later must be different + Thread.Sleep(2); // A snapshot name created 2 milliseconds later must be different var name2 = DependencySnapshotFolderNameTools.CreateUniqueName(); Assert.NotEqual(name1, name2); } @@ -41,7 +41,7 @@ public void NamesConvertedFromInstalledToInstallingDoNotHaveInstalledPostfix() public void UniqueNamesConvertedFromInstalledToInstallingAreStillUnique() { var name1 = DependencySnapshotFolderNameTools.CreateUniqueName(); - Thread.Sleep(1); // A snapshot name created 1 millisecond later must be different + Thread.Sleep(2); // A snapshot name created 2 milliseconds later must be different var name2 = DependencySnapshotFolderNameTools.CreateUniqueName(); var convertedToInstalling1 = DependencySnapshotFolderNameTools.ConvertInstalledToInstalling(name1);