PowerShell サンプル : SharePoint Online HTTP 調整 (応答コード : 429) 対策の増分バックオフ リトライ

こんにちは SharePoint サポートの森 健吾 (kenmori) です。

SharePoint Online に対して CSOM などのクライアント サイド API を大量に呼び出した際、一定期間内における HTTP の要求数やデータ センター側の CPU リソース使用量によっては、一時的なブロックが発生します。

 

2019.3.13 追記 本投稿にて記載したベスト プラクティスはすでに変更されております。以下のページをご確認ください。

[再改訂版] SharePoint Online HTTP 調整 (応答コード : 429) 対策の増分バックオフ リトライ

詳細については、以下のページに記載されています。

タイトル : SharePoint Online で調整またはブロックを回避する方法
アドレス : /ja-jp/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online

この問題が発生することを前提とした有効な対処策として、上記ページではC# を使用した調整を回避するための期間をあけて再実行するための増分バックオフ リトライ コードが紹介されております。

この投稿では、運用シナリオにおいても頻繁に使用される PowerShell 版のサンプルを紹介しますので、ご参考にしてください。

以下のコードでは、$script:context.ExecuteQuery() を自作関数 ExecuteQueryWithIncrementalRetry に置き換えます。

 

 $siteUrl = "https://tenant.sharepoint.com"
# 必要なアセンブリをロードします
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")

# SPO に接続します
$script:context = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)

#ユーザー名入力を促します。
Write-Host "Please input user name : "
$username = read-host

# パスワード入力を促します。
Write-Host "Please input password : "
$password = read-host -assecurestring

$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $password)
$script:context.Credentials = $credentials

function ExecuteQueryWithIncrementalRetry($retryCount, $delay)
{
  $retryAttempts = 0;
  $backoffInterval = $delay;
  if ($retryCount -le 0)
  {
    throw "Provide a retry count greater than zero."
  }
  if ($delay -le 0)
  {
    throw "Provide a delay greater than zero."
  }
  while ($retryAttempts -lt $retryCount)
  {
    try
    {
      $script:context.ExecuteQuery();
      return;
    }
    catch [System.Net.WebException]
    {
      $response = $_.Exception.Response
      if ($response -ne $null -and $response.StatusCode -eq 429)
      {
        Write-Host ("CSOM request exceeded usage limits. Sleeping for {0} seconds before retrying." -F ($backoffInterval/1000))
        #Add delay.
        Start-Sleep -m $backoffInterval
        #Add to retry count and increase delay.
        $retryAttempts++;
        $backoffInterval = $backoffInterval * 2;
      }
      else
      {
        throw;
      }
    }
  }
  throw "Maximum retry attempts {0}, have been attempted." -F $retryCount;
}

# ここから実装したい任意のコードを書きます。
$web = $script:context.Web
$script:context.Load($web)
#$context.ExecuteQuery() を以下に置き換えます。
ExecuteQueryWithIncrementalRetry -retryCount 5 -delay 30000
$web.Title = "RetryTest"
$web.Update()
#$context.ExecuteQuery() を以下に置き換えます。
ExecuteQueryWithIncrementalRetry -retryCount 5 -delay 30000

 

 

ポイント

PowerShell 変数のスコープ ($script:) が本実装のポイントです。今回のサンプル コードでは、ExecuteQueryWithIncrementalRetry 関数内で ClientContext.ExecuteQuery を実行しています。
PowerShell では、関数内と外でスコープが異なる変数はそれぞれ独立したものとして存在します。そのため、関数外で $context.Web.Title などを変更し、関数内で $context.ExecuteQuery() を実行しても更新処理が行われません。

そのため、上記サンプルでは $script: を使用して、該当スクリプトの範囲内で同じスコープの変数であると定義するに至っています。

詳細は以下のページをご確認ください。

タイトル : about_Scopes
アドレス : https://technet.microsoft.com/ja-jp/library/hh847849.aspx

今回の投稿は以上です。