メインコンテンツまでスキップ

Kurocoのバッチ処理を利用する

バッチ処理とは何か

バッチ処理とは、一定時間ごとに実行される処理です。 kurocoでは15分毎、30分毎、1時間毎、毎日のいずれかの頻度でバッチ処理を実行出来ます。

どのような場面で利用できるか

バッチ処理をシステム利用者が少ない夜間や休日などに実行させることによって、システムの負荷を軽減したり、空きリソースを有効利用させることが出来ます。

また、複数のユーザーが同時に操作することによって急激に高負荷がかかってしまう処理などは、バッチ化することによって処理がキューイングされ、1件ずつ順番で実行されるようになるため負荷を軽減することが出来ます。

例えば以下の様な用途があげられます。

  • 外部システムへ連携するためのCSVの生成
  • 外部システムからKurocoへファイル連携によってデータを取り込む処理
  • ユーザーが退会したあとに、システム内のさまざまなデータを更新する処理
  • ログを集計して統計データを算出する

バッチの作成方法

1日1回CSVファイルを出力するバッチ処理を作成してみましょう。

1. バッチ処理の新規作成する

[オペレーション] -> [バッチ処理]をクリックします。

Image from Gyazo

バッチ一覧画面上部にある[追加]ボタンをクリックします。

Image from Gyazo

タイトル欄にバッチ処理の名前「CSV出力」と、識別子欄に「csv_output」と入力します。

Image from Gyazo

2. バッチ処理の実行頻度を指定する

バッチ処理欄からバッチの実行頻度を指定します。 Kurocoでは下記のいずれかから選択できます。

  • 15分毎
  • 30分毎
  • 1時間毎
  • 毎日

今回は、1日1回実行したいので「毎日」を選択し、その隣のプルダウンから「05:00」を選びます。

Image from Gyazo

これで毎朝5:00に実行されるバッチが作成できました。

注意) 「毎日」を選択した場合、前回の最終実行時刻から23時間以上経過していないと処理は実行されません。例えば、動作確認のために「15分毎」に実行し、その直後「毎日」に設定変更したとしても、最終実行時刻は「15分毎」で実行した時刻となります。そこから23時間以内に指定した時刻が訪れる場合、処理はスキップされますのでご注意ください。

3. バッチ処理を実装する

「実行内容」にSmarty構文でバッチ処理を記述していきます。

まずは一時ファイルにヘッダー行を出力します。

{assign var="csv_header" value="記事ID,カテゴリID,カテゴリ名,件名,本文"} {* 注1 *}
{write_file var=tmp_path value=$csv_header|cat:"\n"} {* 注2 *}

注1) assign関数を使って、$csv_headerという変数にCSVのヘッダ行となるカンマ区切りの文字列を保存します。

注2) 続いてその変数を一時ファイルに保存し、ファイル名は$tmp_pathという変数に保存します。write_file関数を使うと自動的にユニークなファイル名を生成してそこに文字を書き出すことが出来ます。

続いて、APIを使って記事一覧を取得します。

{assign var=queries value=$dataSet.emptyArray} {* 注3 *}
{append var=queries index=cnt value=0} {* 注4 *}
{api_internal endpoint='/rcms-api/1/topics-list'
method='GET'
member_id=1
queries=$queries
var='topics_list_response'
}

注3) $queries変数に $dataSet.emptyArray を代入し空配列を準備します。この変数はAPIのクエリー変数として利用します。

注4) つぎにcntというキーに0を代入し,エンドポイント '/rcms-api/1/topics-list' に対してGETメソッドでリクエストを投げます。
'/rcms-api/1/topics-list' はあらかじめ記事一覧モジュールを使って作っておいたエンドポイントを想定してます。
記事一覧に cnt=0 を渡すとページ分割無しで全記事がレスポンスされます。ここでは簡単にするため、その様にしてますが実際にはメモリーエラーの回避のために適切な数値を設定してください。
api_internal関数の member_id 属性に1を渡すと管理者権限でAPIがコールされます。 レスポンスは $topics_list_response という変数に格納されます。

続いて、レスポンスを一時ファイルに追記していきます。

{foreach from=$topics_list_response.list item="topics"} {* 注5 *}
{assign var="row" value=$dataSet.emptyArray} {* 注6 *}
{append var="row" value=$topics.topics_id}{* 記事ID *}
{append var="row" value=$topics.contents_type}{* カテゴリID *}
{append var="row" value=$topics.contents_type_nm|escapeCSV:false:"UTF-8"}{* カテゴリ名 *} {* 注7 *}
{append var="row" value=$topics.subject|escapeCSV:false:"UTF-8"}{* 件名 *}
{append var="row" value=$topics.contents|escapeCSV:false:"UTF-8"}{* 本文 *}
{assign var="row_str" value=","|implode:$row} {* 注8 *}
{write_file path=$tmp_path value=$row_str|cat:"\n" is_append=1} {* 注9 *}
{/foreach}

注5) $topics_list_response.list に記事のデータが配列として格納されてますので、その配列の各要素でループします。

注6) ここでもさきほどと同様に$row という変数を $dataSet.emptyArray(空配列)で初期化し、ヘッダー行の順番通りに配列要素を追加していきます。

注7) マルチバイト文字については追加するときに escapeCSV修飾子を使ってダブルクォーテーションで括る・文字コードをUTF-8に変換するといった処理をおこないます。なお escapeCSVの後ろの:false は改行コードをエスケープするかどうかを指定しています。

注8) $row配列に格納した値をカンマ区切りで文字列結合します。

注9) もう一度write_file関数を使って一時ファイルに8.の文字列+改行コードを追記します。is_append=1を指定するとwrite_file関数は追記モードになります。このとき、path属性を使って一時ファイル名を指定しなければなりませんので、注2)で取得したファイル名を指定しておきます。

最後に一時ファイルをオンラインストレージにアップロードする処理です。

{assign var=csv_path value='/path/to/topics_list.csv'} {* 注10 *}
{assign var="tmp_abs_path" value=$smarty.const.TEMP_DIR2|cat:'/'|cat:$tmp_path} {* 注11 *}
{put_file path=$csv_path tmp_path=$tmp_abs_path} {* 注12 *}

注10) オンラインストレージ上でのファイル名をフルパスで指定します。

注11) 一時ファイルのパスを絶対パスに変換します。一時ファイルはTEMP_DIR2 というパスに保存されてます。

注12) 一時ファイルをオンラインストレージにアップロードします。

完成したスクリプトは以下の様になります。

{assign var="csv_header" value="記事ID,カテゴリID,カテゴリ名,件名,本文"}
{write_file var=tmp_path value=$csv_header|cat:"\n"}

{assign var=queries value=$dataSet.emptyArray}
{append var=queries index=cnt value=0}
{api_internal endpoint='/rcms-api/1/topics-list'
method='GET'
member_id=1
queries=$queries
var='topics_list_response'
}
{foreach from=$topics_list_response.list item="topics"}
{assign var="row" value=$dataSet.emptyArray}
{append var="row" value=$topics.topics_id}{* 記事ID *}
{append var="row" value=$topics.contents_type}{* カテゴリID *}
{append var="row" value=$topics.contents_type_nm|escapeCSV:false:"UTF-8"}{* カテゴリ名 *}
{append var="row" value=$topics.subject|escapeCSV:false:"UTF-8"}{* 件名 *}
{append var="row" value=$topics.contents|escapeCSV:false:"UTF-8"}{* 本文 *}
{assign var="row_str" value=","|implode:$row}
{write_file path=$tmp_path value=$row_str|cat:"\n" is_append=1}
{/foreach}

{assign var=csv_path value='/path/to/topics_list.csv'}
{assign var="tmp_abs_path" value=$smarty.const.TEMP_DIR2|cat:'/'|cat:$tmp_path}
{put_file path=$csv_path tmp_path=$tmp_abs_path}

4. 更新する

記載完了したら、更新ボタンをクリックして内容を保存します。あとは前述の設定時刻の5:00になるのを待ちましょう。 実行されると指定したオンラインストレージ上のパスにファイルが生成されています。

5.テストする方法

debug_print_var修飾子を使うとバッチ編集画面上に変数の内容が出力されます。 ここで第一引数は表示する配列の階層の深さ、第二引数は最大文字列長になります。

{$csv_header|@debug_print_var:0:1000}

「テストする」ボタンクリックすると変更内容を保存せずに、バッチ処理を実行できます。

Image from Gyazo

$csv_header にヘッダ行が保存されていることが確認出来ました。 確認が終わったらdebug_print_varの行は削除しておいてください。


サポート

お探しのページは見つかりましたか?解決しない場合は、問い合わせフォームからお問い合わせいただくか、Slackコミュニティにご参加ください。