1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【UiPath】APIで長時間実行ジョブを検出する

Last updated at Posted at 2025-02-23

この投稿は「UiPath Advent Calendar 2024」の7日目のエントリです。

長時間実行中のジョブ

OCのジョブ管理で「ジョブが実行中のままで、手動で停止する」という時があります。
気付くまでに時間がかかると、後続ジョブのリカバリ対応に追われてしまうため、なるべく早く気づきたい!」という悩みを「APIを使って定期監視することで解決しよう」という話です。

どういう時に、長時間実行になるのか?

そもそも「アクティビティに適切なタイムアウトが設定されていれば、タイムアウトエラーで終了する」はずですが、エラーにならずに実行中のままになることがあります。例えば、

 - ミリ秒のはずが秒で指定していた(指定ミス。待機時間が1000倍に)
 - アクティビティによってはレアなタイミングで、タイムアウト設定が無視されてずっと待機状態になる

いずれも、意図しないケースです。

プロセス実行には「ジョブ開始、トリガー開始、Appsからの実行」などがありますが、トリガーには 「ジョブの実行を終了するスケジュールを設定」 という「開始から一定時間経過で、自動停止させる機能」があります。

image.png


逆に言うと、トリガー以外では、この「長時間動いている場合は自動停止させる」という機能がありません。例えば、OCから手動で再実行した場合や、UiPathAppsの「プロセスを開始」で実行したジョブは、この時限制約が無く、無限に動き続けます。

image.png

ちなみに「Apps経由実行」はその性質上「業務ユーザーに開放している」ことが多く、管理者の監視下にないため、気付くのが遅れてしまいがち。
なので「Apps経由実行」を実現すると、この「長時間実行を検知したい」という課題にぶつかります。

APIで定期的に監視する

長時間実行を監視する方法として、例えば、30分おきにAPIで実行中のジョブを監視して、「2時間以上 実行中 のジョブがないか」をチェックする方法があります。

今回は、どこかのマシンからPowerShellでAPI呼び出しをする想定で実装します。タスクスケジューラーで一定時間おきに実行するように設定すれば、定期監視の出来上がりです。

どこかで勝手に実行して欲しい!という場合は、クラウド契約してサーバーレスで実行かと思いますが、個人的には、PowerAutomateの「スケジュール済みクラウド フロー」で実行するのがオススメです。(安い&作りやすい&他にも色々使い道がある)

コードサンプル

以下は「開始から120分以上経過したジョブがあれば、Slackに通知する」PowerShellのコードです。

# テナントURL
$baseUrl = 'https://cloud.uipath.com/{個別のID}/{テナント名}'

# プライベートアクセストークン
$token = 'rt_・・・・・・(AutomationCloudで取得できます)'

# フォルダー
$ary_folder = @()
$ary_folder += New-Object PSObject -Property @{Id = "6127328"; Name = "管理部"}
$ary_folder += New-Object PSObject -Property @{Id = "6127329"; Name = "マーケ部"}

# しきい値(開始からN分以上経過したジョブがあれば通知)
$th_Minutes = 120

# Slack投稿
$slack_channel = "#uipath"
$slack_token = "xoxb-・・・・・・"

# 実行中ジョブの取得
$ary_job_running = @()
$url = $baseUrl + '/orchestrator_/odata/Jobs?$filter=State%20eq%20''Running''' # 実行中のみ
foreach($folder in $ary_folder){
    $headers = @{"Authorization" = "Bearer " + $token; "X-UIPATH-OrganizationUnitId" = $folder.id}
    $response = Invoke-RestMethod -Uri $url -Method Get -Headers $headers -ContentType "application/json"
    if ($response.StatusCode -lt 300){
        foreach($dat in $response.value){
            $item = New-Object PSObject -Property @{
                StartTime = (Get-Date -Date $dat.StartTime).AddHours(0).ToString("yyyy/MM/dd HH:mm:ss")
                LapseTime = (Get-Date -Date "2000/01/01 00:00:00").AddSeconds((New-TimeSpan -Start $dat.StartTime -End $now).TotalSeconds).ToString("HH:mm:ss")
                LapseMinutes = [Math]::Floor((New-TimeSpan -Start $dat.StartTime -End (Get-Date)).TotalMinutes)
                State = $dat.State
                MachineName = $dat.HostMachineName
                UnitName = $folder.Name
                Name = if($dat.SourceType -eq "Schedule"){ $dat.Source }else{ $dat.ReleaseName } # 実行元が「Schedule(タイムトリガー)」なら実行名
                SourceType = $dat.SourceType
            }
            $ary_job_running += $item
        }
    }else{
         Write-Host $response.StatusCode
         Write-Host $response.StatusDescription
         Throw 'OC-API 呼び出しエラー'
    }
    Write-Host "[GetJob]Sleep - 5 Seconds...(Optional delay between requests)"
    Sleep 5
}

Write-Host ("[Getjob]Result - data count: " + $ary_job_running.count)
$ary_job_running = $ary_job_running | Select-Object "StartTime","LapseTime","LapseMinutes","State","MachineName","UnitName","SourceType","Name" 
$ary_job_running | Format-Table


# N分以上経過に絞り込み
$ary_alert = ""
foreach($job in $ary_job_running){
    if($job.LapseMinutes -ge $th_Minute){
        $ary_alert += $job.StartTime + " 開始 (" + $job.LapseMinutes + "分経過) " + $job.UnitName + "「" + $job.Name + "」@" + $job.MachineName
    }
}
Write-Host ("[Getjob]Filter - data count: " + $ary_alert.count)

# Slack投稿
if($ary_alert.count -gt 0){
    $message = @{channel = $slack_channel; text = ":alarm_clock: 長時間実行中ジョブ検出 ※ 閾値:" + $th_Minute + "分\n" + $ary_alert -join '\n'}
    $response = Invoke-WebRequest -Uri "https://slack.com/api/chat.postMessage" `
                      -Method Post `
                      -ContentType "application/json" `
                      -Headers @{Authorization = "Bearer $slack_token"} `
                      -Body ($message | ConvertTo-Json)
    $response = Invoke-RestMethod -Uri $url -Method Get -Headers $headers -ContentType "application/json"
    Write-Host ("[SlackPost]Response - StatusCode: " + $response.StatusCode)
    if ($response.StatusCode -lt 300){
        Write-Host ("[SlackPost]Response - Content: " + $response.Content)
    }else{
         Write-Host $response.StatusCode
         Write-Host $response.StatusDescription
         Throw 'SlackAPI 呼び出しエラー'
    }
}

OCのAPI「odata/Jobs」から実行中のジョブを取得し、実行開始から一定期間経過したジョブがあれば、Slackに通知しています。
(私はもう少し手を加えて、プロセス名で保守担当を割り出して、メンションをつけて通知する形で運用しています。通知が飛んでくれば 早く気付けるので)

実行結果・出力内容

上記コードを実行すると、長時間実行中のジョブがあれば、指定のSlackチャンネルに通知が投稿されます。

image.png

終わりに

以上、APIで長時間実行ジョブを検出する方法の紹介でした。

OCありの現場で「RPAの本数を増やしたい・規模を拡大したい」場合、無いと困る機能なので、なにかの参考になれば幸いです。(UiPathの標準機能であれば良いんですけどね。)

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?