Azure PowerShell Runbook计划执行挂起及重复执行的问题排查
排查Azure Automation Runbook重复执行及Google Drive上传失败问题
首先咱们先理清核心问题:你的脚本手动测试正常,但按计划执行后触发了3次重试,导致Google Drive出现3份备份副本,而且Invoke-WebRequest之后的日志没输出,说明这个请求可能卡住或未正常完成,触发了Azure Automation的失败重试机制。下面分步骤给你排查建议和解决方法:
1. 抓准Invoke-WebRequest的真实错误
测试环境和Automation沙盒环境有差异,光靠Write-Verbose看不到底层错误,给你的上传代码加个try/catch块,把详细错误打出来:
try { Write-Verbose "Uploading database to google drive using a timeout of 600 seconds..." $uploadrequest = Invoke-WebRequest -method Post -uri $GUploadURI -body $GUploadBody -Headers $Guploadheaders -usebasicparsing -TimeoutSec 600 Write-Verbose "Uploaded database to google drive." } catch { # 把错误细节全打去作业日志,方便定位 Write-Error "上传失败:$($_)" Write-Error "异常详情:$($_.Exception.ToString())" if ($_.Exception.Response) { Write-Error "响应状态码:$($_.Exception.Response.StatusCode.Value__)" Write-Error "响应描述:$($_.Exception.Response.StatusDescription)" } }
另外,Automation沙盒可能有出站网络限制,先加个连通性测试:
Write-Verbose "测试Google Drive API连通性..." try { $testConn = Invoke-WebRequest -Uri "https://www.googleapis.com/drive/v3/about" -UseBasicParsing -TimeoutSec 30 Write-Verbose "连通性测试通过,状态码:$($testConn.StatusCode)" } catch { Write-Error "无法连接Google Drive API:$_" }
2. 优化内存使用,避免沙盒资源限制
你现在把Blob内容存临时文件再读入内存,虽然16MB不算大,但Azure Automation沙盒的内存有上限(超过阈值可能被强制终止),改成直接用Blob流上传,省掉内存加载这一步:
Write-Verbose "直接获取Blob流..." $blob = Get-AzureStorageBlob -Container $container -Blob $blobName -Context $storageContext $stream = $blob.ICloudBlob.OpenRead() try { # 直接把流作为请求体,不用把整个文件加载到内存 $uploadrequest = Invoke-WebRequest -method Post -uri $GUploadURI -Body $stream -Headers $Guploadheaders -usebasicparsing -TimeoutSec 600 Write-Verbose "Uploaded database to google drive." } finally { # 记得关闭流,避免资源泄漏 $stream.Close() }
这样能大幅降低内存占用,避免因为沙盒资源不足导致作业被终止。
3. 阻止Runbook重试的两种方法
方法一:调整Runbook的重试策略
直接在Azure门户里改:
- 进入你的Automation账户,找到目标Runbook
- 点击左侧作业,查看失败作业的重试记录,然后进入Runbook的设置 -> 作业设置
- 把重试次数改成0,这样即使作业失败也不会自动重试
方法二:给脚本加幂等性检查
即使重试触发,也不会重复上传:
# 生成唯一的备份标识(数据库名+时间戳) $backupId = "$($databaseName)_$(Get-Date -Format 'yyyyMMddHHmmss')" $markerBlobName = "$backupId.uploaded" # 检查Blob容器里是否已有这个标记文件,有就直接退出 $markerExists = Get-AzureStorageBlob -Container $container -Blob $markerBlobName -Context $storageContext -ErrorAction SilentlyContinue if ($markerExists) { Write-Verbose "备份$backupId已经上传过了,直接退出" exit 0 } # 执行备份到Blob的逻辑... # 上传到Google Drive成功后,在Blob容器创建标记文件 $null = New-AzureStorageBlob -Container $container -Blob $markerBlobName -Context $storageContext -Value "上传成功"
这样就算Runbook重试,也会因为检测到标记文件直接退出,不会生成重复副本。
内容的提问来源于stack exchange,提问作者The Senator
相关产品推荐
相关产品推荐

