You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix potential call depth overflow error when retrying a 202 response (#294)
GitHub will return back a `202` response when the result for the query is not yet ready. GitHub requests that we "give the job a few moments to complete, and then submit the request again."
We already had the configuration value `RetryDelaySeconds` which covered how many seconds we would sleep before trying the request again. We tried the request again via a recursive call to `Invoke-GHRestMethod`.
It turns out that there's something going on with GitHub right now, and trying to get contributor statistics for a completely new repository never returns back a 200, even after 145 retry attempts over 72 minutes.
That many recursive calls ends up causing a call depth overflow exception with PowerShell. While this scenario should be an edge-case, nonetheless it seems better to remove the possibility of this error from occurring by modifying the retry logic to be a loop rather than a recursive call.
I've also added a new configuration value: `MaximumRetriesWhenResultNotReady` to help control and limit the number of retries that we'll attempt in this situation, ultimately throwing an exception if the retry limit is exceeded without a 200 response.
Finally, I've disabled the `When getting Github Repository Contributors with Statistics` test until the problem is fixed on the GitHub end. I've disabled the test by commenting the test out vs using the disable keyword to avoid the Pester failure for disabled tests, and I've opened a [support issue](https://github.community/t/unable-to-retrieve-contributor-statistics-for-a-brand-new-repo/136658) on this problem.
# In some cases, the returned data might have two different keys of the same characters
330
+
# but different casing (this can happen with gists with two files named 'a.txt' and 'A.txt').
331
+
# PowerShell 6 introduced the -AsHashtable switch to work around this issue, but this
332
+
# module wants to be compatible down to PowerShell 4, so we're unable to use that feature.
333
+
Write-Log-Message 'The returned object likely contains keys that differ only in casing. Unable to convert to an object. Returning the raw JSON as a fallback.'-Level Warning
334
+
$finalResult=$finalResult
335
+
}
336
+
catch [ArgumentException]
337
+
{
338
+
# The content must not be JSON (which is a legitimate situation).
339
+
# We'll return the raw content result instead.
340
+
# We do this unnecessary assignment to avoid PSScriptAnalyzer's PSAvoidUsingEmptyCatchBlock.
341
+
$finalResult=$finalResult
319
342
}
320
-
}
321
-
catch [InvalidOperationException]
322
-
{
323
-
# In some cases, the returned data might have two different keys of the same characters
324
-
# but different casing (this can happen with gists with two files named 'a.txt' and 'A.txt').
325
-
# PowerShell 6 introduced the -AsHashtable switch to work around this issue, but this
326
-
# module wants to be compatible down to PowerShell 4, so we're unable to use that feature.
327
-
Write-Log-Message 'The returned object likely contains keys that differ only in casing. Unable to convert to an object. Returning the raw JSON as a fallback.'-Level Warning
328
-
$finalResult=$finalResult
329
-
}
330
-
catch [ArgumentException]
331
-
{
332
-
# The content must not be JSON (which is a legitimate situation).
333
-
# We'll return the raw content result instead.
334
-
# We do this unnecessary assignment to avoid PSScriptAnalyzer's PSAvoidUsingEmptyCatchBlock.
335
-
$finalResult=$finalResult
336
-
}
337
343
338
-
if ((-not$Save) -and (-not (Get-GitHubConfiguration-Name DisableSmarterObjects)))
339
-
{
340
-
# In the case of getting raw content from the repo, we'll end up with a large object/byte
341
-
# array which isn't convertible to a smarter object, but by _trying_ we'll end up wasting
342
-
# a lot of time. Let's optimize here by not bothering to send in something that we
343
-
# know is definitely not convertible ([int32] on PS5, [long] on PS7).
344
-
if (($finalResult-isnot [Object[]]) -or
345
-
(($finalResult.Count-gt0) -and
346
-
($finalResult[0] -isnot [int]) -and
347
-
($finalResult[0] -isnot [long])))
344
+
if ((-not$Save) -and (-not (Get-GitHubConfiguration-Name DisableSmarterObjects)))
345
+
{
346
+
# In the case of getting raw content from the repo, we'll end up with a large object/byte
347
+
# array which isn't convertible to a smarter object, but by _trying_ we'll end up wasting
348
+
# a lot of time. Let's optimize here by not bothering to send in something that we
349
+
# know is definitely not convertible ([int32] on PS5, [long] on PS7).
# We only want to do our retry logic for GET requests...
395
+
# We don't want to repeat PUT/PATCH/POST/DELETE.
396
+
Write-Log-Message "The server has indicated that the result is not yet ready (received status code of [$($result.StatusCode)])."-Level Warning
397
+
}
398
+
elseif ($retryDelaySeconds-le0)
363
399
{
364
-
$nextLink=$Matches[1]
365
-
$nextPageNumber= [int]$Matches[2]
400
+
Write-Log-Message "The server has indicated that the result is not yet ready (received status code of [$($result.StatusCode)]), however the module is currently configured to not retry in this scenario (RetryDelaySeconds is set to 0). Please try this command again later."-Level Warning
Write-Log-Message "The server has indicated that the result is not yet ready (received status code of [$($result.StatusCode)]). Will retry in [$retryDelaySeconds] seconds. $($maxiumRetriesPermitted-$numRetriesAttempted) retries remaining."-Level Warning
$message="Request still not ready after $numRetriesAttempted retries. Retry limit has been reached as per configuration value 'MaximumRetriesWhenResultNotReady'"
413
+
Write-Log-Message $message-Level Error
414
+
throw$message
377
415
}
378
416
}
379
-
}
380
-
381
-
$resultNotReadyStatusCode=202
382
-
if ($result.StatusCode-eq$resultNotReadyStatusCode)
if (($stateChangeDelaySeconds-gt0) -and ($Method-in$stateChangeMethods))
387
424
{
388
-
# We only want to do our retry logic for GET requests...
389
-
# We don't want to repeat PUT/PATCH/POST/DELETE.
390
-
Write-Log-Message "The server has indicated that the result is not yet ready (received status code of [$($result.StatusCode)])."-Level Warning
425
+
Start-Sleep-Seconds $stateChangeDelaySeconds
391
426
}
392
-
elseif ($retryDelaySeconds-le0)
427
+
428
+
if ($ExtendedResult)
393
429
{
394
-
Write-Log-Message "The server has indicated that the result is not yet ready (received status code of [$($result.StatusCode)]), however the module is currently configured to not retry in this scenario (RetryDelaySeconds is set to 0). Please try this command again later."-Level Warning
Write-Log-Message "The server has indicated that the result is not yet ready (received status code of [$($result.StatusCode)]). Will retry in [$retryDelaySeconds] seconds."-Level Warning
399
-
Start-Sleep-Seconds ($retryDelaySeconds)
400
-
return (Invoke-GHRestMethod@PSBoundParameters)
452
+
return$finalResult
401
453
}
402
454
}
403
-
404
-
# Allow for a delay after a command that may result in a state change in order to
405
-
#increase the reliability of the UT's which attempt multiple successive state change
0 commit comments