[Talend] エラーとなる可能性のある処理をリトライする

2016.08.26

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

特定の処理でエラー(例外)が発生した際にリトライしたいケースありますよね?数秒ほど何らかの理由でデータベースへアクセスができない状態となった時など、数秒間置いてリトライする処理が組まれていれば全体の処理を止めずに完了することができます。そのような処理を Talend で作ってみました。

概要

今回作成したジョブの完成形は下図の通りです。

talend-error-retry_000

「リトライ」と銘打たれた(線で見難いですが……)コンポーネントから反復(Iterate)線で繋がれた処理が「エラーとなる可能性のある処理(下図の赤枠内)」となります。

talend-error-retry_001

今回は Redshift へアクセスし、「SELECT 'Hello, world!' AS message;」というクエリの結果を tLogRow でコンソールへ表示するだけの処理です。

エラー(例外)が発生した場合は、指定された試行回数・試行間隔でリトライを行い、成功した場合には「成功」ダイアログを、リトライに失敗した場合には「失敗」ダイアログを表示するように組み立てました。

talend-error-retry_002

試行回数・試行間隔の設定

試行回数(tryTimes)および試行間隔(tryInterval)は「コンテキスト」に設定しました。「コンテキスト」はそのジョブ全体で使われる値を設定しておける場所です。

talend-error-retry_003

  1. 「追加ボタン」を押下し、
  2. 追加された行の「Name」に名称を付け、
  3. データの型を指定し、
  4. 「Value」に実値を入力します。

ここでは試行回数(tryTimes)を 3 回、試行間隔(tryInterval)を 10 秒と設定しました。

リトライ処理の作成(tJavaFlex)

リトライ処理の実現にはコンポーネント「tJavaFlex」を使用します。

talend-error-retry_004

このコンポーネントは Java コードが書ける「tJava」系のコンポーネントですが、コードを書くエリアが「開始コード」「メインコード」「終了コード」に分かれている所が変わっている点です。

ここに下図のように Java コードを書きます。

talend-error-retry_005

開始コード

int count = 0;
while (true) {
    count++;
    try {

メインコード

        System.out.println("Try count: " + count);

終了コード

        break;
    } catch (Exception e) {
        if (context.tryTimes <= count) {
            throw e;
        }
        TimeUnit.SECONDS.sleep(context.tryInterval);
    }
}

繋げると

int count = 0;
while (true) {
    count++;
    try {
        // メインコード ここから
        System.out.println("Try count: " + count);

        // ★★★ エラーとなる可能性のある処理 ★★★

        // メインコード ここまで
        break;
    } catch (Exception e) {
        if (context.tryTimes <= count) {
            throw e;
        }
        TimeUnit.SECONDS.sleep(context.tryInterval);
    }
}

となります。

TimeUnit を使っているので、詳細設定のインポート欄に import 文を記述します。

talend-error-retry_006

処理としては、無限ループ内の try-catch 文で例外が発生した場合、試行回数を満たさない間は試行間隔(秒数)スリープ後にリトライ、試行回数を満たしたらキャッチした例外をそのまま throw する処理となっています。

メインコードに書かれたコードが無限ループの対象となりますが、tJavaFlex コンポーネントから「反復(Iterate)」線で繋がれた処理も対象となります。前述コードの「/* ★★★ エラーとなる可能性のある処理 ★★★ */」に処理が入るイメージですね。

tMsgBox コンポーネント(おまけ)

今回は成功・失敗の通知を tMsgBox を使って行うようにしました。

talend-error-retry_007

設定値はそれぞれ下図のような感じです。

talend-error-retry_008

実行

まずは普通に実行してみます。

talend-error-retry_009

成功しました!

次にネットワーク接続を切って実行してみます。

talend-error-retry_010

ジョブ Retry を 17:40 26/08/2016 に開始しました。
[statistics] connecting to socket on port 4069
[statistics] connected
Try count: 1
Try count: 2
Try count: 3
Exception in component tRedshiftConnection_1
java.sql.SQLException: [Amazon](500150) Error setting/closing connection: UnknownHostException.
	at com.amazon.redshift.client.PGClient.connect(PGClient.java:537)
	at com.amazon.redshift.client.PGClient.<init>(PGClient.java:329)
	at com.amazon.redshift.core.PGJDBCConnection.connect(PGJDBCConnection.java:534)
	at com.amazon.jdbc.common.BaseConnectionFactory.doConnect(Unknown Source)
	at com.amazon.jdbc.common.AbstractDriver.connect(Unknown Source)
	at java.sql.DriverManager.getConnection(DriverManager.java:664)
	at java.sql.DriverManager.getConnection(DriverManager.java:247)
	at sample_project.retry_0_1.Retry.tJavaFlex_1Process(Retry.java:488)
	at sample_project.retry_0_1.Retry.runJobInTOS(Retry.java:1431)
Caused by: com.amazon.support.exceptions.GeneralException: [Amazon](500150) Error setting/closing connection: UnknownHostException.
	... 9 more
Caused by: java.net.UnknownHostException
	at sun.nio.ch.Net.translateException(Net.java:155)
	at sun.nio.ch.SocketAdaptor.connect(SocketAdaptor.java:127)
	at com.amazon.redshift.client.PGClient.connect(PGClient.java:504)
	at com.amazon.redshift.client.PGClient.<init>(PGClient.java:329)
	at com.amazon.redshift.core.PGJDBCConnection.connect(PGJDBCConnection.java:534)
	at com.amazon.jdbc.common.BaseConnectionFactory.doConnect(Unknown Source)
	at com.amazon.jdbc.common.AbstractDriver.connect(Unknown Source)
	at java.sql.DriverManager.getConnection(DriverManager.java:664)
	at java.sql.DriverManager.getConnection(DriverManager.java:247)
	at sample_project.retry_0_1.Retry.tJavaFlex_1Process(Retry.java:488)
	at sample_project.retry_0_1.Retry.runJobInTOS(Retry.java:1431)
	at sample_project.retry_0_1.Retry.main(Retry.java:1269)
[statistics] disconnected
ジョブ Retry が 17:41 26/08/2016 に終了しました。 [終了コード=0]

三回リトライしてちゃんと失敗になりました。

最後に、ネットワーク接続が切れた状態で実行開始し、「Try count: 2」が表示されたらネットワークを接続してみます。

talend-error-retry_011

三回目のリトライで成功しました!

意図的にエラーを発生

「エラーとなる可能性のある処理」は何でもよいので、tJava コンポーネントなどで意図的に例外を発生させても動作確認が可能です。

ここでは tJava コンポーネントでゼロ除算をさせて例外を発生させてみました。

double dbz = 1 / 0;

talend-error-retry_012

期待通り三回リトライして失敗になりましたね。

まとめ

このように tJavaFlex コンポーネントひとつでリトライ処理が実現できるので、大事な処理はこのコンポーネントから繋いでおくとよいでしょう。
また、今回使った tJavaFlex コンポーネントの使い方はこれ限りというわけではありませんので、またの機会に記事の題材として取り上げられればと思います。