Skip to content

Commit 3773306

Browse files
authored
⚡ Add cache for origin requests
1 parent 7346fc9 commit 3773306

File tree

1 file changed

+25
-11
lines changed

1 file changed

+25
-11
lines changed

ModuleFast.psm1

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ using namespace System.Reflection
1616
using namespace System.Text
1717
using namespace System.Threading
1818
using namespace System.Threading.Tasks
19+
using namespace System.Runtime.Caching
1920

2021
#Because we are changing state, we want to be safe
2122
#TODO: Implement logic to only fail on module installs, such that one module failure doesn't prevent others from installing.
@@ -276,8 +277,8 @@ function Install-ModuleFast {
276277
switch ($PSCmdlet.ParameterSetName) {
277278
'Specification' {
278279
foreach ($ModuleToInstall in $Specification) {
279-
$duplicate = $ModulesToInstall.Add($ModuleToInstall)
280-
if ($duplicate) {
280+
$isDuplicate = -not $ModulesToInstall.Add($ModuleToInstall)
281+
if ($isDuplicate) {
281282
Write-Warning "$ModuleToInstall was specified twice, skipping duplicate"
282283
}
283284
}
@@ -1315,6 +1316,8 @@ enum HashtableType {
13151316

13161317
#region Helpers
13171318

1319+
#This is used as a simple caching mechanism to avoid multiple simultaneous fetches for the same info. For example, Az.Accounts. It will persist for the life of the PowerShell session
1320+
[MemoryCache]$SCRIPT:RequestCache = [MemoryCache]::new('PowerShell-ModuleFast-RequestCache')
13181321
function Get-ModuleInfoAsync {
13191322
[CmdletBinding()]
13201323
[OutputType([Task[String]])]
@@ -1337,14 +1340,19 @@ function Get-ModuleInfoAsync {
13371340
$ModuleId = $Name
13381341

13391342
#This call should be cached by httpclient after first attempt to speed up future calls
1340-
#TODO: Only select supported versions
1341-
#TODO: Cache this index more centrally to be used for other services
13421343
Write-Debug ('{0}fetch registration index from {1}' -f ($ModuleId ? "$ModuleId`: " : ''), $Endpoint)
1343-
if (-not $SCRIPT:__registrationIndex) {
1344-
$SCRIPT:__registrationIndex = $HttpClient.GetStringAsync($Endpoint, $CancellationToken).GetAwaiter().GetResult()
1344+
$endpointTask = $SCRIPT:RequestCache[$Endpoint]
1345+
1346+
if ($endpointTask) {
1347+
Write-Debug "REQUEST CACHE HIT for Registration Index $Endpoint"
1348+
} else {
1349+
$endpointTask = $HttpClient.GetStringAsync($Endpoint, $CancellationToken)
1350+
$SCRIPT:RequestCache[$Endpoint] = $endpointTask
13451351
}
13461352

1347-
$registrationBase = $SCRIPT:__registrationIndex
1353+
$registrationIndex = $endpointTask.GetAwaiter().GetResult()
1354+
1355+
$registrationBase = $registrationIndex
13481356
| ConvertFrom-Json
13491357
| Select-Object -ExpandProperty resources
13501358
| Where-Object {
@@ -1353,13 +1361,19 @@ function Get-ModuleInfoAsync {
13531361
| Sort-Object -Property '@type' -Descending
13541362
| Select-Object -ExpandProperty '@id' -First 1
13551363

1356-
$uri = "$registrationBase/$($ModuleId.ToLower())/$Path"
1364+
$Uri = "$registrationBase/$($ModuleId.ToLower())/$Path"
13571365
}
13581366

1359-
#TODO: System.Text.JSON serialize this with fancy generic methods in 7.3?
1360-
Write-Debug ('{0}fetch info from {1}' -f ($ModuleId ? "$ModuleId`: " : ''), $uri)
1367+
$requestTask = $SCRIPT:RequestCache[$Uri]
13611368

1362-
return $HttpClient.GetStringAsync($uri, $CancellationToken)
1369+
if ($requestTask) {
1370+
Write-Debug "REQUEST CACHE HIT for $Uri"
1371+
} else {
1372+
Write-Debug ('{0}fetch info from {1}' -f ($ModuleId ? "$ModuleId`: " : ''), $uri)
1373+
$requestTask = $HttpClient.GetStringAsync($uri, $CancellationToken)
1374+
$SCRIPT:RequestCache[$Uri] = $requestTask
1375+
}
1376+
return $requestTask
13631377
}
13641378

13651379
function Add-DestinationToPSModulePath {

0 commit comments

Comments
 (0)