programing

PowerShell 시도/잡기 및 재시도

oldcodes 2023. 10. 11. 20:58
반응형

PowerShell 시도/잡기 및 재시도

저는 다양한 동작을 수행하는 많은 (20개 이상) 기능을 가진 꽤 큰 파워셸 스크립트를 가지고 있습니다.

지금은 모든 코드에 오류 처리나 재시도 기능이 없습니다.특정 작업/기능이 실패하면 실패하고 계속 진행합니다.

오류 처리를 개선하고 재시도를 실행하여 보다 견고하게 만들고 싶습니다.

이런 생각을 하고 있었습니다.

$tries = 0
while ($tries -lt 5) {
    try{    

       # Do Something

       # No retries necessary
       $tries = 5;
    } catch {
       # Report the error
       # Other error handling
    }
 }

문제는 제가 이 일을 해야 할 단계가 많다는 것입니다.

위 코드를 20번 시행하는 것은 말이 안 된다고 생각합니다.그것은 정말 불필요한 것 같습니다.

제가 전화하고 싶은 실제 기능이 포함된 단일 파라미터로 "TryCatch" 기능을 작성하려고 생각했는데요?

저도 그것이 올바른 접근법인지 잘 모르겠습니다.결국 다음과 같은 내용이 적힌 스크립트로 끝이 나지 않을까요?

TryCatch "Function1 Parameter1 Parameter2"
TryCatch "Function2 Parameter1 Parameter2"
TryCatch "Function3 Parameter1 Parameter2"

더 좋은 방법이 없을까요?

동작을 여러 번 재시도하는 코드가 자주 필요한 경우 루프를 감쌀 수 있습니다.try..catch함수에서 명령을 스크립트 블록에 전달합니다.

function Retry-Command {
    [CmdletBinding()]
    Param(
        [Parameter(Position=0, Mandatory=$true)]
        [scriptblock]$ScriptBlock,

        [Parameter(Position=1, Mandatory=$false)]
        [int]$Maximum = 5,

        [Parameter(Position=2, Mandatory=$false)]
        [int]$Delay = 100
    )

    Begin {
        $cnt = 0
    }

    Process {
        do {
            $cnt++
            try {
                # If you want messages from the ScriptBlock
                # Invoke-Command -Command $ScriptBlock
                # Otherwise use this command which won't display underlying script messages
                $ScriptBlock.Invoke()
                return
            } catch {
                Write-Error $_.Exception.InnerException.Message -ErrorAction Continue
                Start-Sleep -Milliseconds $Delay
            }
        } while ($cnt -lt $Maximum)

        # Throw an error after $Maximum unsuccessful invocations. Doesn't need
        # a condition, since the function returns upon successful invocation.
        throw 'Execution failed.'
    }
}

다음과 같은 기능을 실행합니다(기본값은 5회 재시도).

Retry-Command -ScriptBlock {
    # do something
}

또는 이와 같이(경우에 따라 다른 양의 재시도가 필요한 경우):

Retry-Command -ScriptBlock {
    # do something
} -Maximum 10

기능은 예를 들어 다음 후에 스크립트를 종료함으로써 더욱 향상될 수 있습니다.$Maximum다른 매개 변수를 사용하여 구성할 수 있는 실패한 시도를 통해 실패할 때 스크립트가 중지되는 작업뿐만 아니라 실패를 무시할 수 있는 작업도 수행할 수 있습니다.

@Victor의 대답을 개작하고 다음과 같이 덧붙였습니다.

  • 재시도에 대한 매개변수
  • ErrorAction set and restore(또는 예외가 잡히지 않음)
  • 지수 백오프 지연 (OP에서 이것을 요청하지 않은 것은 알고 있지만 사용합니다.
  • VSCode 경고 제거(즉, 교체)sleep와 함께Start-Sleep)
# [Solution with passing a delegate into a function instead of script block](https://stackoverflow.com/a/47712807/)
function Retry()
{
    param(
        [Parameter(Mandatory=$true)][Action]$action,
        [Parameter(Mandatory=$false)][int]$maxAttempts = 3
    )

    $attempts=1    
    $ErrorActionPreferenceToRestore = $ErrorActionPreference
    $ErrorActionPreference = "Stop"

    do
    {
        try
        {
            $action.Invoke();
            break;
        }
        catch [Exception]
        {
            Write-Host $_.Exception.Message
        }

        # exponential backoff delay
        $attempts++
        if ($attempts -le $maxAttempts) {
            $retryDelaySeconds = [math]::Pow(2, $attempts)
            $retryDelaySeconds = $retryDelaySeconds - 1  # Exponential Backoff Max == (2^n)-1
            Write-Host("Action failed. Waiting " + $retryDelaySeconds + " seconds before attempt " + $attempts + " of " + $maxAttempts + ".")
            Start-Sleep $retryDelaySeconds 
        }
        else {
            $ErrorActionPreference = $ErrorActionPreferenceToRestore
            Write-Error $_.Exception.Message
        }
    } while ($attempts -le $maxAttempts)
    $ErrorActionPreference = $ErrorActionPreferenceToRestore
}

# function MyFunction($inputArg)
# {
#     Throw $inputArg
# }

# #Example of a call:
# Retry({MyFunction "Oh no! It happened again!"})
# Retry {MyFunction "Oh no! It happened again!"} -maxAttempts 10

스크립트 블록 대신 함수에 위임자를 전달하는 솔루션:

function Retry([Action]$action)
{
    $attempts=3    
    $sleepInSeconds=5
    do
    {
        try
        {
            $action.Invoke();
            break;
        }
        catch [Exception]
        {
            Write-Host $_.Exception.Message
        }            
        $attempts--
        if ($attempts -gt 0) { sleep $sleepInSeconds }
    } while ($attempts -gt 0)    
}

function MyFunction($inputArg)
{
    Throw $inputArg
}

#Example of a call:
Retry({MyFunction "Oh no! It happend again!"})

오류 처리는 일반적으로 여러 가지를 처리해야 하므로 스크립트에 항상 더 많은 것을 추가합니다.각 함수에 여러 번 시도하도록 하려면 Try Catch 함수가 위에서 설명한 내용에 가장 적합할 것입니다.사용자 지정 함수를 사용하면 매번 값을 전달하여 시도 간에 슬립 타이머와 같은 것을 설정하거나, 함수가 시도할 시도 횟수를 변경할 수도 있습니다.

언급URL : https://stackoverflow.com/questions/45470999/powershell-try-catch-and-retry

반응형