ServiceNowで定時起動処理からキューを使って非同期の処理をキックする

# 概要

下記のデータ整理バッチはデータ整理対象を設定テーブルからデータ整理対象テーブルと保持日数のレコードを読み込んで、その設定レコードごとに同期でレコードの削除処理を起動している。

[ServiceNowでデータ整理バッチ処理を作成する](https://qiita.com/sukkyxp/items/2bce405c75d03d2ccdf9)

今回は、設定テーブルのレコードごとのループ処理までは同じだが、実際にレコードを削除する処理をキューの仕組みを使って非同期で起動する。
設定レコードごとのループでは、キューに非同期処理を起動するためのキューにイベントを登録するだけで、次の設定レコードの処理に進むことができる。
キューを使って非同期で削除処理を起動するため、キューにイベントを登録するループを抜けたところで実際にデータ整理が完了しているかどうかは分からない。

また、ここでキューと呼んでいる仕組みはServiceNowの「Event Registry」と「Script Action」のレコード作成と、「gs.eventQueue」のGlideSystemのAPI起動を使って実現している。
Evnet Registryがキューのレコードで、「gs.eventQueue」でこのキューにイベントを登録している。
「Script Action」はこのキューにイベントが登録された時に起動する処理となっている。

|構成要素 | 役割|
|---|---|
|Event Registry| キュー|
|gs.eventQueue |キューにイベント登録|
|Script Action |キューにイベントが登録されたら起動される|

## 環境

ServiceNow:KINGSTONE

# 手順

## Event Regitry（キュー）の作成

StudioでCreate Application Fileで「Server Category」の「Event Registration」を選択してCreateをクリックする。

下記の通り、Tableは選択しない。「Suffix」に名前を入力してSubmitで保存する。

![EventRegistration.png](https://qiita-image-store.s3.amazonaws.com/0/197947/27071d65-f79e-a2e3-dc5d-56fdc80e522b.png)

Event nameは入力したSuffixから自動生成される。
イベント登録のAPIではこのEvent nameを使用するのでコピーしておく。

## Script Actionの作成（キューから起動される処理)

StudioのCreate Application Fileで「Server Category」の「Script Action」を選択してCreateをクリックする。

下記の通り入力してSubmitをクリックする。Nameは任意の名前を入力する。
Event Nameは上で作成したEvent RegistryのEvent Nameを選択する。
また、初期状態でActiveのチェックがはずれているのでActiveを設定する。

![ScriptAction.png](https://qiita-image-store.s3.amazonaws.com/0/197947/912c69e7-eae2-eed0-5603-da5b725d514a.png)

スクリプトに次のように入力する。

```javascript
	// 整理対象テーブル名
	var tableName = current.getValue('tablename');
	// 整理対象日付判定用の列名
	var periodColumnName = current.getValue('periodcolumnname');
	// 保持期限（日数）
	var period = current.getValue('period');
	
	// 整理対象日付を「本日日付 - 保持期限（日数）」で算出
	var expiredDate = new GlideDateTime();
	expiredDate.addDaysLocalTime(Number(period * -1));
	
	gs.info('データ整理アクション処理開始:テーブル = ' + tableName +  ', 期限切れ日 = ' + expiredDate.getLocalDate());

	var reductionRecord = new GlideRecord(tableName);
	// 整理対象テーブルを「判定用の列名 <= 整理対象日付」で抽出 
	reductionRecord.addQuery(periodColumnName, '<=', expiredDate);
	reductionRecord.query();
	// 処理対象件数をあらかじめ取得しておく
	var targetCount = reductionRecord.getRowCount();
	
	gs.info('処理件数 = ' + targetCount);
	// 一括削除実行
	reductionRecord.deleteMultiple();
```

ここで「current」はイベント登録にに渡されるGlideRecord型のオブジェクトだ。
次のキューへのイベント登録処理で、データ整理対象設定のレコードを引数で設定する。

## バッチ処理からキューにイベント登録

Schedule Script Excecutionを作成し、Scriptに次の通り入力する。
これがバッチ処理のメイン処理になる。

```javascript
// 整理対象設定テーブルからレコードを読み込む
var reductionSettingsRecord = new GlideRecord('x_211750_angular_a_datareductionsettings');
reductionSettingsRecord.query();


while (reductionSettingsRecord.next()) {
	// 整理対象テーブル名
	var tableName = reductionSettingsRecord.getValue('tablename');
	// 保持期限（日数）
	var period = reductionSettingsRecord.getValue('period');
		gs.eventQueue('x_211750_angular_a.expiredDataDeleteEven',reductionSettingsRecord, tableName, period);
	
}
```

「gs.eventQueue」の部分がこの処理のキモの部分だ。
１つ目の引数はEvent Regitrationで作成したキューの名前なので、作成時にコピーしておいた名前を貼り付ける。
２つ目の引数は、任意のGlideRecordを渡すことができる。
次の２つの引数はここでは、キューのログを確認時に表示されるので、分かりやすい値を設定しておく。

このようにキューにイベントを登録することにより、キューに紐づけられたScript Actionは非同期で起動される。
gs.eventQueueはキューにイベントを登録するだけなので、Script Actionの起動をまたずに、次の行に処理が移る。

## 実行して動作確認

Schedule Script Excecutionで作成したバッチ処理の設定画面の「Execute Now」をクリックしてバッチ処理を起動する。

Eventログを確認する。Studioではなく、ServiceNowブラウザーのナビゲーションで「Event」を入力して、「System Logs」の「Events」を選択してログを確認する。
Param1とParam2には、gs.eventQueueの３つ目、４つ目の引数が表示されている。

![EventLog.png](https://qiita-image-store.s3.amazonaws.com/0/197947/11c7d3af-dc19-6e13-6533-277ad45c6c8d.png)

# 最後に

Event Registrationの登録項目にTableとQueueというものがあるが、これが直接処理にどのように結び付いているのか不明な点が残っている。
また、Fired byとDescriptionもどちらも単に説明として使用するのであれば、２つある必要は無いので、使い分けがあるはずだが、これも不明だ。
今後、判明すれば内容を改定する予定だ。