web-dev-qa-db-ja.com

PowerShellの試行/キャッチと再試行

さまざまなアクションを実行する多くの(20以上の)関数を含むかなり大きなpowershellスクリプトがあります。

現在、すべてのコードには実際にはエラー処理や再試行機能はありません。特定のタスク/機能が失敗した場合、失敗して続行します。

エラー処理を改善し、再試行を実装してより堅牢にしたいと考えています。

私はこれに似たものを考えていました:

$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"

これを行うより良い方法はありますか?

12
Brad

アクションを何度も再試行するコードが頻繁に必要な場合は、ループされたtry..catchを関数にラップして、コマンドをスクリプトブロックに渡すことができます。

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

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

    Begin {
        $cnt = 0
    }

    Process {
        do {
            $cnt++
            try {
                $ScriptBlock.Invoke()
                return
            } catch {
                Write-Error $_.Exception.InnerException.Message -ErrorAction Continue
            }
        } 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の失敗後にスクリプトを終了することにより、別のパラメーターを使用して構成を試行できるため、スクリプトが失敗したときにスクリプトを停止させるアクションと、失敗を無視できるアクションを持つことができます。

6
Ansgar Wiechers

スクリプトブロックではなく関数にデリゲートを渡すソリューション:

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!"})
0
Victor

エラー処理は、通常、多くの異なる処理を行う必要があるため、スクリプトに常に追加されます。 Try Catch関数は、各関数に複数の試行を持たせたい場合、おそらく上記の説明に最も適しています。カスタム関数を使用すると、毎回値を渡すことで、試行間のスリープタイマーなどを設定したり、関数が試行する試行回数を変更したりできます。

0
Jason Snell