Java EE 7から加わるバッチ仕様

Batch Applications for
 the Java Platform - JSR 352




                      7
                      Java EE




                        Java Batch
Batch Applications
        for the Java Platform (JSR 352)

   Java EE 7から導入されるバッチフレームワーク
   Spring Batch のアーキテクチャを踏襲
   アーキテクチャ定義のもと、APIとXMLの仕様を定義

JSR352 の構成 (Public Review時点)


 アーキテクチャ仕様 Job/Step/Chunk      アーキテクチャ全体像を定義
       (第4章)



ジョブXML仕様           API仕様       アーキテクチャを
  (第5章)            (第6章)       『どうやって』実装するか


                                         Java Batch
Java Batchの主な機能1 - 実行順序制御

       ジョブXMLと呼ばれる設定で、処理手順を定義する
       処理の分岐、グループ化、並列実行が可能
start
         STEP1      Flow (ステップ グループ化)

                     STEP2-1      STEP2-2


                                                  end
                       STEP3-1
   Decision(条件分岐)
                                   Flow
                      Split




                                   Flow

                                   Flow
                              Split (ステップの並行実行)     Java Batch
Java Batchの主な機能2 - 分割コミット


   レコード数が多い場合は、チェックポイントは必須要件
   後述するchunk処理方式によって分割コミットを実現


                                      ロールバックは最終コミットまで


                commit       commit       commit          end
                                                    ×
    start
                  ▼            ▼            ▼

            10行処理        10行処理        10行処理        障害発生




                                                        Java Batch
Java Batchの主な機能3 - エラーハンドリング

   バッチ失敗のよくある原因は不正な入力データ
   Java Batch ではエラーレコードを自動スキップする


                    1, AAA, BBB, CCC
                    2, DDD, EEE, FFF
                    ???,,,,aaa,,aeae,   スキップ
                    3, JJJ, KKK, LLL

                                …
     バッチプログラム
                   99, ZZZ, ZZZ, ZZZ


                                         Java Batch
Java Batchの主な機能4 - 並行・分散実行

   仕様上は明記されていないが、分散実行も可能?
   引数にExternalizableを持つAPIがいくつかある
    (オブジェクトのシリアル化を意識している)

                  Server B

     Server A        STEP2-1   STEP2-2


      STEP1
                  Server C

                     STEP3-1   STEP3-2



                                         Java Batch
ジョブスケジューラ と JavaBatch

   Java Batchには、cronのような時刻起動する機能はない
   cronやJP1から、Java Batchを呼び出して使う
   順序管理のように被る領域もある (使い分け整理が必要)


    スケジューリング
    (時刻・周期起動)
                  ジョブ実行順序管理             ジョブ実装サポート
                      JP1:ジョブネット
                    JavaBatch:ジョブXML     (フレームワーク)
    実行権限の管理


            ジョブスケジューラ
          (cron/JP1/Tivoliなど)   Java Batch   Java Batch
Java Batch の位置付け
   起動元は従来からあるバッチスケジューラ
   バッチAPの開発を簡単にするAPI提供がJava Batchの役割
    ジョブスケジューラ
     (Cron/JP1など)

                          ユーザ作成の
      時刻起動               アプリケーション
                                       各種APIの提供
                                                   データベース
               Servlet    JPA     Java Batch

               アプリケーションサーバ (JBoss等)

                          OS/Java VM                 ファイル
                                                  (CSV/XML 等)

                                                   Java Batch
アーキテクチャ

     7
     Java EE




       Java Batch
アーキテクチャ

   JCLやCOBOLディベロッパに馴染み深いアーキテクチャ
   バッチ処理をメインフレームからJavaに移管させるため、
    昔からある考え方をベースとした。



                  Job
                              STEP2-1
    JobOperator    STEP1                STEP3   STEP4
                              STEP2-1




                        JobRepository

                                                Java Batch
ジョブ

   バッチ階層の最上位要素
   複数のステップを組み合わせてジョブを構成する
   ステップ全体に関わる設定はジョブに定義する
    (例 : リスタート制御)

                  Job
                              STEP2-1
    JobOperator    STEP1                STEP3   STEP4
                              STEP2-1




                        JobRepository

                                                Java Batch
ジョブをXMLで表現すると

                      ジョブの識別子。
                  JobOperator経由で起動時に
                      このidを指定する。


<job id="samplejob" restartable="false">
    <step id="step1" next="step2" />
    <step id="step2" />
</job>




                                  Java Batch
ジョブをXMLで表現すると

    ジョブがリスタート可能か。
  デフォルトはtrueのオプション属性。
    (リスタートについては後述)


<job id="samplejob" restartable="false">
    <step id="step1" next="step2" />
    <step id="step2" />
</job>




                                  Java Batch
ジョブをXMLで表現すると

            処理したいステップを定義。
          Next属性で次のステップを指定。
      (順序制御は色々種類があるので、後で詳しく解説)


<job id="samplejob" restartable="false">
    <step id="step1" next="step2" />
    <step id="step2" />
</job>




                                  Java Batch
ジョブインスタンスの考え方

   JobInstance
    1日1回のジョブであれば、毎日1つずつ生成される。
    次の日にリスタートする場合は、前日のインスタンスを使う。
   JobExecution
    実行ごとに生成される。リスタート時には新たに生成される。


      Job       『ファイル取り込み』ジョブ

            *
        JobInstance    2007/05/05 に実行する
        JobInstance    『ファイル取り込み』ジョブ

                  *
            JobExecution   2007/05/05 に実行する
            JobExecution   『ファイル取り込み』ジョブ の1回目
                                          Java Batch
ジョブとリスタート

   1つのジョブインスタンスは、データとの対応を持つ
   例えば、1月1日のジョブインスタンスは、1月2日に
    リスタートしても1月1日分のデータにアクセスする。
   対象データが違うため、前日のリスタートジョブと
    当日のジョブは並行実行することも可能。

    1月1日分のジョブ
    JobInstance
                              実行      1/1のデータ   ◎
                          回目の
                    1/1 1
           *                     行    1/2のデータ   △
                           タ ート実
                    1/2 リス      /1分   1/3のデータ   ×
                          ート時も1
     JobExecution
     JobExecution   リスタ タを処理
                    のデー
     実行インスタンスは
      実行毎に生成                               Java Batch
ステップ

   ジョブに含まれるタスクを定義する。
   各ステップの内容は、ユーザがコーディングする。
   図のように、条件によって分岐することもできる。


                  Job
                              STEP2-1
    JobOperator    STEP1                STEP3   STEP4
                              STEP2-1




                        JobRepository

                                                Java Batch
ステップ : 2つの処理方式

   Chunk 方式
   Batchlet方式

                                    Item
        STEP       ItemReader    Processor      ItemWriter           STEP                batchlet
execute()                                                    execute()
               read()
                                                                             process()
                item

                        process(item)

                item
                                        writer(item)                        ExitStatus

                                                             ExitStatus
ExitStatus



                Chunk方式                                                   Batchlet方式
                                                                                  Java Batch
Chunk方式

   大規模なデータ処理に適した処理方式
 1件ずつ読み込んで処理するのでメモリ消費を抑える

 コミット間隔の調整もしやすい


                                    Item
        STEP       ItemReader    Processor      ItemWriter

execute()
               read()                                        Chunk = 出力の塊 を示す
                item

                        process(item)
                                                             複数レコードを処理して一度に
                                                             出力することも可能である。
                item
                                                             (詳細は次スライドで紹介)
                                        writer(item)


ExitStatus

                                                                         Java Batch
Chunk方式 : まとめてコミット

     オーバヘッド低減のため、書き込みはまとめることも可能。
             (chunk-size属性の設定)

                                    Item
        STEP       ItemReader    Processor      ItemWriter

execute()
               read()
                item
                        process(item)          1アイテム目の読み込みと処理
                item
               read()
                item
                        process(item)          2アイテム目の読み込みと処理
                item

                                        writer(items)
                                                             処理が終わった2アイテムを
ExitStatus                                                   書き込み、コミット

                                                                     Java Batch
Chunk方式 : アノテーション

     Reader/Processor/Writerはユーザがコード作成する。

 ItemReader
              のコード例
 @Named
 public class MyItemReader {
   @ReadItem
   MyBatchInputRecord read() throws Exception {
     // レコード読み取り処理
   }
 }

SpringBatchはインタフェースをベースに作成するが、
JavaBatchでは、@ReadItemのようにアノテーション対応。

                                           Java Batch
Chunk方式 : CDIとの連携

       JavaBatchではSpringDIの代わりにCDIが使われる

ItemReader
             のコード例
@Named
public class MyItemReader {
  @ReadItem
  MyBatchInputRecord read() throws Exception {
    // レコード読み取り処理
  }
}

全てのコンポーネントに、@java.inject.Namedが必要。
ジョブXMLからコンポーネント名を指定するため。

                                          Java Batch
Chunk方式 : ジョブXML例

   ステップの子要素としてchunkを定義する
   reader/processor/writer属性にはクラス名を定義
   チャンクサイズの設定もXMLで可能 (デフォルトは10)



<job id="samplejob" restartable="false">
  <step id="step1" next="step2" >
    <chunk reader="MyReader" processor="MyProcessor"
           writer="MyWriter" chunk-size="2" />
  </step>
  <step id="step2" />
</job>

                                             Java Batch
Batchlet方式

   ファイル/DB処理ではないステップに使う
   ファイル圧縮・転送・各種OSコマンドの実行 など
   Spring Batchのtaskletを同等のもの

            STEP                batchlet

    execute()
                   process()


                                           Chunkと比べて非常にシンプル。
                                           STEPとbatchletが1対1となる。
                   ExitStatus

    ExitStatus



                                                           Java Batch
Batchlet方式 : @Process

    @Processを付けたメソッドに処理を記述するだけ


@Named
public class MyBatchLet{
    @Process
    String process() throws Exception {...}
    @Stop
    void stopMe() throws Exception {...}
}
@Process

  バッチレットの処理内容を定義する
@Stop

  JobOperator#stop()されたときにコールバックされる

                                              Java Batch
Batchlet方式 : ジョブXML例

   ステップの子要素としてbatchletを定義する
   batchletを実装したクラス名を参照先として設定する


    <job id="samplejob" restartable="false">
      <step id="step1" next="step2" />

       <batchlet ref="MyBatchlet" />

      </step>
      <step id="step2" />
    </job>
                                          Java Batch
リスナ : ジョブ・ステップ実行前後にコールバック

   ジョブやステップの実行前後に呼び出される
 一時ディレクトリ掃除・再生成などの前準備に使える
 複数のリスナを定義することが可能


ジョブレベルリスナ                                                       ジョブレベルリスナ
 (ジョブ実行前)                                                        (ジョブ実行後)



               Job




                                                                        listener
    listener




                        STEP2-1
                                  listener




                                                     listener
                STEP1                        STEP3              STEP4
                        STEP2-1


                                      ステップレベルリスナ
                                       (ジョブ実行前後)
                                                                    Java Batch
JobOperator

   ジョブはジョブオペレータにより起動/再起動/停止される
   バッチ処理のコントロール役




                  Job
                              STEP2-1
    JobOperator    STEP1                STEP3   STEP4
                              STEP2-1




                        JobRepository

                                                Java Batch
JobOperator : API

   BatchRuntimeクラスからインスタンスは取得できる
   先ほどXMLで指定したジョブIDを起動のキーとする

// factoryでインスタンスを取得
JobOperator jobOperator = BatchRuntime.getJobOperator();

// ジョブIDを指定して、ジョブを起動
jobOperator.start("jobid1", property);



        <job id="jobid1">

                                                Java Batch
JobRepository

   ジョブやステップの実行状態を保存する
   保存された状態にはJobOperator経由でアクセスする
   前述した、リトライ用のジョブインスタンスはここに保存


                  Job
                              STEP2-1
    JobOperator    STEP1                STEP3   STEP4
                              STEP2-1




                        JobRepository

                                                Java Batch
実行順序の制御

      7
      Java EE




        Java Batch
ステップ実行手順は複数の手段がある
    Flow - ステップのグループ化
    Sprit – 並行実行するフローの組み合わせを定義
    Decision – ステップの終了ステータスに応じた条件分岐
start
         STEP1        Flow (ステップ グループ化)

                       STEP2-1      STEP2-2


                                                    end
                         STEP3-1
     Decision(条件分岐)
                                     Flow
                        split




                                     Flow

                                     Flow
                                split (ステップの並行実行)    Java Batch
もっともシンプルなケース

1つのジョブに、ステップが順処理で2つ
 start                       end
         STEP1    STEP2


                          next属性に次ステップを指定。
                          idが対象。

<job id="samplejob">
  <step id="step1" next="step2" />
  <step id="step2" />
</job>


                                     Java Batch
Flow

    ステップを一連のユニットとしてまとめる
    フローが終了したあとは、次エレメントに遷移
    (ステップ、スプリット、デシジョン、他のフローのいずれか)

    start            Flow                           end
             STEP1      STEP2-1   STEP2-1   STEP3


<job id="samplejob">
    <step id="step1">
    <flow id="flow1" next="step3"> フローの中に複数ステップを定義。
        <step id="step2-1"/>
        <step id="step2-2"/>       next属性には、フローが完了した
    </flow>                        あとの次のステップを定義する。
    <step id="step3" />
</job>
                                                Java Batch
Split : 3つの構成要素

   Split : 並列実行するフローの組み合わせを定義
   Split Collector :
       フロー実行結果を受け取り Split Analyzer に送る。
   Split Analyzer :
     Split Collectorから受け取った並行実行結果を処理する。



                  Flow   Split Collector
start                                                          end
                                             split
        split




                  Flow   Split Collector              STEP2
                                           analyzer
                  Flow   Split Collector




                                                          Java Batch
Split : ジョブXMLの書き方

   スプリットの中に並列実行したいフローを定義する
   各フローは別々のスレッドで実行される

    <job id="samplejob">
        <split id="split1" next="step2">
            <flow id="flow1">
                 <step id="step1-1-1" next="step1-1-2"/>
                 <step id="step1-1-2"/>
            </flow>
            <flow id="flow2">
                 <step id="step1-2-1" next="step1-2-2"/>
                 <step id="step1-2-2"/>
            </flow>
        </split>
        <step id="step2" />
    </job>
                                                      Java Batch
Split Collector

   フロー結果をスプリットアナライザに中継する役割
   各スプリットしたフローの実行スレッドで動作
   FlowContextからデータを集め、Externalizableで返す



                FlowContextで
                   受け渡し                   Externalizableで
                                              受け渡し
                 Flow   Split Collector
start                                                               end
                                              split
        split




                 Flow   Split Collector                     STEP2
                                            analyzer
                 Flow   Split Collector



                                                               Java Batch
Split Collector : @CollectSplitData
@Named                                    コンテキストは自動的に
public class SplitCollector {             インジェクションされる
    @BatchContext
    FlowContext flowContext;
                                   Split Collector を示すアノテーション
     @CollectSplitData
     Externalizable collectSplitData() throws Exception {
         // コンテキストからFlowデータの取得
         FlowData flowData = flowContext.getTransientUserData();

         // Externalizable実装のユーザクラスを生成
         ExternalizableBookData serial = new ExternalizableBookData();
         serial.setName(flowData.getBookName());

         // Externalizableを返す
         return serial;
     }
                                     外部化(Externalizable)の結果を返す
}
Memo.
仕様書には『The FlowContext is in scope when this method receives control.』とあるが、
Split Collectorがどうやって各スプリットの結果を受け取るかはうまく読み取れていない。
読み取れる範囲からは、上記のようにコンテキストからデータ取得すると思われる。                                     Java   Batch
参考 : java.io.Externalizable
   Serializableを継承したインタフェース
   オブジェクトの外部出力を自分でコーディングする。
public class Book implements Externalizable {

    String title; int price;    引数なしコンストラクタを忘れると
                                復元時に InvalidClassException が
    public Book() {}            投げられるので注意。
    public Book(String title, int price) {
        this.title = title; this.price = price;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeUTF(title); out.writeInt(price);
    }                                             書き出し処理

    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        title = in.readUTF(); price = in.readInt();
    }                                               復元処理
}                                                                      Java Batch
Split Analyzer

   Split Collectorから並行実行したフロー結果を集約する。
   Collectorと異なり、シングルスレッドで動作する。
   Collectorからデータが送られるたびに複数回起動する。

                                     Split Collectorから
                                     各フロー結果を受け取る

                Flow   Split Collector
start                                                               end
                                           split
        split




                Flow   Split Collector                     STEP2
                                         analyzer
                Flow   Split Collector
                                                     集約・分析結果を出力




                                   ファイル             DBMS
                                                               Java Batch
Split Analyzer : @AnalyzeCollectorData

@Named                         SplitContextにアクセスできる
public class SplitAnalyzer {
    @BatchContext                  Collectorから受け取ったデータを分析。
    SplitContext splitContext;     Collectorが書き出し回数分繰り返し呼ばれる。
                                              (3スプリットであれば、3回呼ばれる)
     @AnalyzeCollectorData
     void analyze(Externalizable data) throws Exception{
         // SplitCollectorから受け取ったデータを分析
     }
                               バッチステータスやスプリットの終了コードに
     @AnalyzeStatus            応じた処理を定義する。
     void analyzeStatus(String batchStatus, String exitStatus)
       throws Exception {
         // スプリットの終了ステータスに応じた処理を行う
     }
}

Memo.
仕様書には『The analyzeCollectorData method receives control each time a Partition collector sends its
payload.』と書かれていて、この解釈をCollectorからデータが送られるたびに毎回起動されると解釈した。
一方、Analyzerはシングルスレッド起動としても明記されているため、一度に複数のCollectorからデータが送られた
場合の挙動が仕様書からはうまく読み取れていない。
                                                                                  Java Batch
CollectorとAnalyzer : ジョブXMLの書き方

<job id="samplejob">
    <split id="split1" next="step2">
        <flow id="flow1">
            <step id="step1-1-1" next="step1-1-2"/>
            <step id="step1-1-2"/>
        </flow>
        <flow id="flow2">
            <step id="step1-2-1" next="step1-2-2"/>
            <step id="step1-2-2"/>
        </flow>

        <collector ref="SplitCollector" />
        <analyzer ref="SplitAnalyzer" />

    </split>            Splitエレメントの子エレメントとして定義。
    <step id="step2" /> 参照先の実装クラス名をrefに指定する。
</job>
                                                      Java Batch
Decision

   ステップ・フロー・スプリットの終了ステータスをもとに
    次の遷移先を選択する。

   全部で4種類の遷移を指定できる
     <next> : 次エレメントへ遷移 <end> : 正常終了
     <fail> : 異常終了                      <stop> : 一時停止

                             <next on=”*” to=”STEP2”>
                                                           STEP2

     start                  Decision
                                                <end on=”stop step”>
             STEP1
                     exit status
                                                                       end

                                   <fail on=”fail step”>   ×
                                                           異常終了
                                                                   Java Batch
バッチステータス と 終了ステータス
   バッチステータス
     ジョブ全体の現在の状態を定義するパラメータ
     状態の種類は仕様で定義されている
     バッチランタイムにより設定される



   終了ステータス                Desicionの判定対象
     ジョブ・ステップ・フロー・スプリットの終了ステータス
     文字列値をユーザで定義する
     ユーザが設定する。
      何も設定されていない場合は、バッチステータスと同じ値。
                               Step          Step
                            exit status   exit status
        start                                 end
                                                        Job exit status
                   STEP1       STEP2

                Batch Status (バッチ全体の現在の状態)
                                                                          Java Batch
終了ステータスの設定方法
   コンテキストのAPIで設定する
 リスナーで設定すると、Chunk処理と分離できて便利

@Named
public class StepListener {
    @BatchContext
    StepContext stepContext;

    @BeforeStep
    public void beforeStep() throws Exception {
        // なんらかの前処理をする
    }                               Stepから特定の例外が投げられた場合に
                                   終了ステータスを設定する。
    @AfterStep
    public void afterStep() throws Exception {
        if (stepContext.getException() instanceof InvalidRecordException) {
            stepContext.setExitStatus("failed cause invalid records");
        }
    }
}
Memo.
仕様書にはリスナのコンテキストについて言及されていない。ステップ・リスナにはステップ・コンテキストが
インジェクションできると思うが、上記のコードは推測の域である。
                                                                     Java Batch
参考 : バッチステータス一覧

ステータス値                           意味

            バッチジョブは、ジョブオペレータのでスタートまたはリスタート操作されると、バッチ
 STARTING   ランタイムによりSTARTING状態とされます。
            ステップにおいても、実行開始直前はSTARTING状態となります。

            バッチジョブがバッチランタイムにより既に開始されている状態です。
 STARTED    ステップにおいても、一度実行された後はSTARTED状態となります。

            バッチジョブが、ジョブオペレータの停止操作、またはジョブXMLの<stop>エレメントに
 STOPPING   よって停止要求された状態です。ステップにおいても、STOPPING状態となった場合は、
            バッチランタイムによりまもなく停止処理が行われます。
            バッチジョブが、ジョブオペレータの停止操作、またはジョブXMLの<stop>エレメントに
 STOPPED    よって停止した状態です。ステップにおいても、バッチランタイムに停止された場
            合、STOPPED状態となります。

            バッチジョブが、未解決の例外、またはジョブXMLの<fail>エレメントによって終了した
  FAILED    状態です。ステップにおいても同様の条件でFAILED状態となります。


            バッチジョブが、正常終了、またはジョブXMLの<end>エレメントによって終了した状態
COMPLETED   です。ステップにおいても同様の条件でCOMPLETED状態となります。

            バッチジョブが、ジョブオペレータの『放棄(avandoned)』操作が行われたことを示す状
ABANDONED   態です。放棄状態のジョブはジョブオペレータ経由で確認することはできますが、実行や
            リスタートを行うことはできません。履歴閲覧を目的に確認できるようになっています。


                                                 Java Batch
Decision : @Decide

   メソッド引数でコンテキストを取得する
 終了コードを判定し、条件に応じて終了コードを上書き

                              終了コードが SUCCESS の場合、
@Named                        SKIP に上書きする。
public class Decider {
    @Decide
    public String decide(BatchContext context)
            throws Exception {

        String exitStatus = context.getExitStatus();
        if ("SUCCESS".equals(exitStatus)) {
            return "SKIP";
        }
        return exitStatus;
    }
}
                                                   Java Batch
Decision : ジョブXMLの書き方

   Decisionではスキップの決定など動的な遷移制御ができる。


                    refにはDeciderのクラス名を設定
<job id="samplejob">
    <step id="step1">
        <decision id="decision1" ref="Decisider">
            <next on="SKIP" to="step3"/>
            <next on="*" to="step2"/>
        </decision>
    </step>
    <step id="step2" next="step3"/> DeciderからSKIPが返された場合は
                                    step3に進む。
    <step id="step3">
</job>                              それ以外はstep2に進む。



                                                Java Batch
実行順序の制御 : まとめ

    ジョブXMLとAPIを駆使して、様々な遷移が可能
 主な手段として Flow、Decision、Split の3種類がある。

    start
             STEP1      Flow (ステップ グループ化)

                         STEP2-1      STEP2-2


                                                       end
                           STEP3-1
       Decision(条件分岐)
                                       Flow
                          split




                                       Flow

                                       Flow
                                  split (ステップの並行実行)   Java Batch
例外ハンドリング

      7
      Java EE




        Java Batch
バッチ失敗の原因 : 不正なレコード

不正なレコートが1行あっただけで、バッチ全体が失敗する


バッチプログラム                  処理対象のファイル
                         Name, Age, Address
               SUCCESS
                         山田, 29, 千葉
               SUCCESS
                         佐藤, 46, 埼玉
               SUCCESS
                                 (数万行続く...)




                                      ...
               FAIL
                         破壊,,aaa,,99,,,




 Status FAIL


                                              Java Batch
バッチ失敗の原因 : 一時的に繋がらない

DBセッションが一時的に足りないだけで、翌日に再実行。



                        100 Session


         ジョブA                     Max Session = 200
                90 Session



                                 ×
  ジョブB
                                一時的な過負荷により
                                DBセッション数が足りない

            ジョブC
                                                  Java Batch
バッチ失敗の原因 : パーミッションがない

  ディレクトリや一時ファイルの作成に失敗する。



                  一般ユーザ
                   拒否
                           ×
      一時ファイル
                           root権限のディレクトリ
バッチプログラム
 (一般ユーザ)          mk
                    di r

           グループ書き込み権が ×
              足りない   パーミッション744の
                               ディレクトリ



                                        Java Batch
Java Batch 3つのエラーハンドリング

   スキップ
       不正な入力データをスキップして、処理を継続
   Chunk方式のステップが対象
    
 リトライ
     一時的な要因により失敗した処理を再実行
     セッション不足、ロック待ち など
 リスタート
       深刻なエラーが発生した場合はジョブを失敗させる
       原因を取り除き、手動で再起動する




                                  Java Batch
スキップ
  Java Batchには次レコードにスキップしても良い例外を登録
   (ジョブXMLに例外クラス名を記述)
 ItemReaderから投げられた例外がスキップ対象か判定する。
 デフォルトは例外が1つでも発生すると、ジョブは失敗する


JavaBatchランタイム                       Chunk方式
                          2.例外スロー                         Name, Age, Address
 スキップ対象例外                            ItemReader 1. 例外
                                                     発生   山田, 29, 千葉
InvaliedRecordException
                          3.スキップ許可                        破壊,,aaa,,99,,,
     xxx Exception
                                                          佐藤, 54, 埼玉
    △△△ Exception                                                   4. スキップ
                                        Item              田中, 25, 東京
                                     Processor

                                                          不正レコードを含んだ
                                       Item                 入力ファイル
                                       Writer

                                                                    Java Batch
スキップ : <skippable-exception-classes>

<job id="samplejob" restartable="false">    スキップ上限数を設定
  <step id="step1" next="step2" >
    <chunk reader="MyReader" processor="MyProcessor"
           writer="MyWriter" skip-limit="10">

    <skippable-exception-classes>
      <include class="java.io.IOException" />
      <exclude class="java.net.SocketException" />
    </skippable-exception-classes>

    </chunk>                           スキップ対象の例外を設定。
  </step>                              子クラスも対象になるので、
  <step id="step2" />                 excludeで除外対象も要指定。
</job>

デフォルトは1つでも例外発生した時点でジョブ失敗。
必ずスキップ対象例外を設定すること。
ファイル全体が不正なものに備えて、スキップ上限数も必ず設定する。
                                                     Java Batch
スキップリスナ : @OnSkipedReadItem

   どのレコードをスキップしたのか記録することは重要
   スキップ契機のリスナーであるスキップリスナでロギング
    @Named
    public class SkipListener {

         private static final Logger logger
             = Logger.getLogger(SkipListener.class);

         @OnSkipReadItem
         public void onSkipReadItem(Exception ex)
                 throws Exception {

             // エラーメッセージのロギング
             logger.log(ex.getMessage());
         }
    }
                                                       Java Batch
スキップリスナ : ジョブXMLの書き方

<job id="samplejob" restartable="false">
    <step id="step1" next="step2" >
      <chunk reader="MyReader" processor="MyProcessor"
             writer="MyWriter" skip-limit="10">
        <skippable-exception-classes>
            <include class="java.io.IOException" />
            <exclude class="java.net.SocketException" />
        </skippable-exception-classes>
      </chunk>
      <listeners>
          <listener ref="SkipListener" />
      </listeners>
    </step>
    <step id="step2" />         スキップリスナはステップ階層の
</job>                              リスナとして登録する。
                                ref属性にはクラス名を指定。


                                                 Java Batch
ItemProcessorで例外が発生したら?

   チャンクサイズ分、まとめて読み込まれる。
   例外発生するとチャンク全体をロールバック。
   読み込み済キャッシュは再利用される。

                                     ロールバック


 chunk size分読み込み
<chunk chunk-size=”x”>   Cash Item      Process

      Read Item
     Read Item           Cash Item      Process   Write Item
     Read Item
                         Cash Item      Process

                                           トランザクション区間


                                                        Java Batch
ItemProcessor例外 : スキップ方法

   キャッシュからアイテムをロードして再処理
   例外の原因となったアイテムはスキップする


                 キャッシュからロード

                   Cash Item    Process

     Read Item
    Read Item      Cash Item   スキップ       Write Item
    Read Item
                   Cash Item    Process

                                   トランザクション区間      ▲
                                                 commit


                                                   Java Batch
ItemWriterで例外が発生したら?

    Writerは処理したデータをまとめて受け取る
    どの入力がエラーの原因になったのかわからない
      → スキップ対象のItemを特定しにくいのが特徴

                             ロールバック


                         ?
             Cash Item       Process

 Read Item   Cash Item
                         ?   Process       Write Item
Read Item
Read Item
                         ?
             Cash Item       Process
                                       @WriteItems
                                       writeItems(List<T> items);

                                                        Java Batch
ItemWriter例外 : スキップ方法

    1アイテムずつキャッシュから読み込み処理
    例外が発生したアイテムをスキップする
      → Processorと異なり、再度例外発生させてスキップ


                 Cash Item     Process   Write Item

                   1アイテムずつトランザクションを分ける             ▲
                                                 commit

     Read Item
    Read Item
    Read Item
                 Cash Item     Process   Write Item   ×   例外アイテム

                             スキップ

                 Cash Item     Process   Write Item
                                                   ▲
                                                 commit
                                                           Java Batch
リトライ
     一時的な原因の例外に対して効果的
      (ネットワーク不安定/DBロック待ち など)
     リトライを繰り返すと、性能に影響を与えるので注意
     チャンク単位でリトライする
                                                 インターネット
            Cash Item    Process
Read Item
Read Item
Read Item   Cash Item    Process   Write Item         ×
            Cash Item    Process                     接続失敗

                        チャンク単位でリトライ
                                                                Web
            Cash Item    Process                成功             Service
            Cash Item    Process   Write Item
            Cash Item    Process

  外部のWebサービスは繋がりにくい場合もあるので、リトライが効果的
                                                            Java Batch
リトライ : <retryable-exception-classes>

<job id="samplejob" restartable="false">     リトライ回数を設定
  <step id="step1" next="step2" >
    <chunk reader="MyReader" processor="MyProcessor"
           writer="MyWriter" retry-limit="3">

    <retryable-exception-classes>
      <include class="javax.xml.ws.soap.SOAPFaultException" />
      <exclude class="xxxException" />
    </retryable-exception-classes>

    </chunk>                           リトライ対象の例外を設定。
  </step>                              子クラスも対象になるので、
  <step id="step2" />                 excludeで除外対象も要指定。
</job>

retry-limitを設定しない場合、デフォルトではリトライし続ける。
必ずretry-limitに値を設定すること。

                                                        Java Batch
リトライリスナ : @OnRetryWriteException

   スキップと同様に、リトライもロギングが重要
   リトライリスナをユーザが実装してロギングする

@Named
public class RetryListener {

    private static final Logger logger
        = Logger.getLogger(RetryListener.class);

    @OnRetryWriteException
    public void onRetryWriteException(List<T> items,Exception ex)
            throws Exception {

         // エラーメッセージのロギング
         logger.log(ex.getMessage());
    }
}

                                                         Java Batch
リトライリスナ : ジョブXMLの書き方


<job id="samplejob" restartable="false">
    <step id="step1" next="step2" >
       <chunk reader="MyReader" processor="MyProcessor"
              writer="MyWriter" skip-limit="10">
           <retryable-exception-classes>
             <include class="javax.xml.ws.soap.SOAPFaultException" />
             <exclude class="xxxException" />
           </retryable-exception-classes>
       </chunk>
       <listeners>
           <listener ref="RetryListener" />
       </listeners>
    </step>
    <step id="step2" />                リトライリスナはステップ階層の
</job>                                    リスナとして登録する。
                                       ref属性にはクラス名を指定。


                                                          Java Batch
リトライとスキップを組み合わせる
  リトライとスキップは通常組み合わせて設定する
  例: 3回リトライして、失敗する場合は10回までスキップ


<job id="samplejob" restartable="false"> リトライ回数           スキップ上限数
    <step id="step1" next="step2" >
       <chunk reader="MyReader" processor="MyProcessor"
              writer="MyWriter" retry-limit="3" skip-limit="10">
           <retryable-exception-classes>
             <include class="javax.xml.ws.soap.SOAPFaultException" />
           </retryable-exception-classes>
           <skippable-exception-classes>
             <include class="javax.xml.ws.soap.SOAPFaultException" />
           </skippable-exception-classes>
       </chunk>
    </step>
    <step id="step2" />
                             同じ例外をretryable-exception-classesと
</job>                        skippable-exception-classesに設定する

                                                          Java Batch
リスタート

 失敗したステップから再開する機能
 スキップやリトライで対処できない問題に対応
  (オペレータが手を入れないと治らない問題)
 チャンク処理内でのリスタートも可能



                        × ディスクフル発生
      STEP1    STEP2     STEP3       STEP4

    対向システムから    解凍       集計処理     次システムへ
     ファイル取得                      集計データ転送

             リスタート       STEP3       STEP4
          (STEP3から再開)
                        集計処理      次システムへ
                                 集計データ転送


                                             Java Batch
allow-start-if-complete の設定
   業務によっては、ステップを1からやり直したい
   ジョブXMLへの設定で、ステップが完了していた場合に
    再実行するか設定ができる

    途中から再開(デフォルト)                           最初から再開
            STEP1                              STEP1



            STEP2                              STEP2




            STEP3                              STEP3

<step id="step1"                   <step id="step1"
 allow-start-if-complete="true">    allow-start-if-complete="false">

                                                         Java Batch
リスタート : ジョブXML

 restartable属性 : ジョブごとにリスタート可能か設定
 Start-limit属性 : ステップごとにリスタート上限数を設定


                       リスタート可能か?
                    (オプション。デフォルトtrue)


<job id="samplejob" restartable="true">
  <step id="step1" next="step2"
    start-limit="5" />   リスタート上限回数
  <step id="step2" next="step3"
    allow-start-if-complete="false"/>
  <step id="step3" />
</job>              完了していても再実行時に動かすか

                                          Java Batch
エラーハンドリングのポイント

          いかに『堅牢なバッチ』を作るかがポイント

   堅牢とは
     少々のエラーデータが混じっていても落ちない
     一時的なエラーであれば自動的に復旧
       オペレータの手をかけないバッチが堅牢なバッチ

   Java Batch が提供する手段
       スキップ : 不正データのスキップ
       リトライ : 一時的なエラーに対する自動再試行
       リスタート : 途中から再開することで、再実行コスト低減

                                 Java Batch
あとがき

       7
       Java EE




         Java Batch
2013年上半期に仕様はfinalへ

   Public Reviewをもとに調査した
     2013/1 現在は前述した仕様群は作業中
     仕様確定に向けて、まだ内容は修正される可能性も


   Java EE 7 へ盛り込みへ
       次のJava EE 仕様である『7』に盛り込まれる予定
       Java EE 7 も2013年内にはリリース予定
       EE 7 - GlashFishリリースまで、SpringBatchとの差分調査は難しい


        Javaで大規模バッチ構築のために、期待する標準です。



                                             Java Batch

Java Batch 仕様 (Public Review時点)

  • 1.
    Java EE 7から加わるバッチ仕様 BatchApplications for the Java Platform - JSR 352 7 Java EE Java Batch
  • 2.
    Batch Applications for the Java Platform (JSR 352)  Java EE 7から導入されるバッチフレームワーク  Spring Batch のアーキテクチャを踏襲  アーキテクチャ定義のもと、APIとXMLの仕様を定義 JSR352 の構成 (Public Review時点) アーキテクチャ仕様 Job/Step/Chunk アーキテクチャ全体像を定義 (第4章) ジョブXML仕様 API仕様 アーキテクチャを (第5章) (第6章) 『どうやって』実装するか Java Batch
  • 3.
    Java Batchの主な機能1 -実行順序制御  ジョブXMLと呼ばれる設定で、処理手順を定義する  処理の分岐、グループ化、並列実行が可能 start STEP1 Flow (ステップ グループ化) STEP2-1 STEP2-2 end STEP3-1 Decision(条件分岐) Flow Split Flow Flow Split (ステップの並行実行) Java Batch
  • 4.
    Java Batchの主な機能2 -分割コミット  レコード数が多い場合は、チェックポイントは必須要件  後述するchunk処理方式によって分割コミットを実現 ロールバックは最終コミットまで commit commit commit end × start ▼ ▼ ▼ 10行処理 10行処理 10行処理 障害発生 Java Batch
  • 5.
    Java Batchの主な機能3 -エラーハンドリング  バッチ失敗のよくある原因は不正な入力データ  Java Batch ではエラーレコードを自動スキップする 1, AAA, BBB, CCC 2, DDD, EEE, FFF ???,,,,aaa,,aeae, スキップ 3, JJJ, KKK, LLL … バッチプログラム 99, ZZZ, ZZZ, ZZZ Java Batch
  • 6.
    Java Batchの主な機能4 -並行・分散実行  仕様上は明記されていないが、分散実行も可能?  引数にExternalizableを持つAPIがいくつかある (オブジェクトのシリアル化を意識している) Server B Server A STEP2-1 STEP2-2 STEP1 Server C STEP3-1 STEP3-2 Java Batch
  • 7.
    ジョブスケジューラ と JavaBatch  Java Batchには、cronのような時刻起動する機能はない  cronやJP1から、Java Batchを呼び出して使う  順序管理のように被る領域もある (使い分け整理が必要) スケジューリング (時刻・周期起動) ジョブ実行順序管理 ジョブ実装サポート JP1:ジョブネット JavaBatch:ジョブXML (フレームワーク) 実行権限の管理 ジョブスケジューラ (cron/JP1/Tivoliなど) Java Batch Java Batch
  • 8.
    Java Batch の位置付け  起動元は従来からあるバッチスケジューラ  バッチAPの開発を簡単にするAPI提供がJava Batchの役割 ジョブスケジューラ (Cron/JP1など) ユーザ作成の 時刻起動 アプリケーション 各種APIの提供 データベース Servlet JPA Java Batch アプリケーションサーバ (JBoss等) OS/Java VM ファイル (CSV/XML 等) Java Batch
  • 9.
    アーキテクチャ 7 Java EE Java Batch
  • 10.
    アーキテクチャ  JCLやCOBOLディベロッパに馴染み深いアーキテクチャ  バッチ処理をメインフレームからJavaに移管させるため、 昔からある考え方をベースとした。 Job STEP2-1 JobOperator STEP1 STEP3 STEP4 STEP2-1 JobRepository Java Batch
  • 11.
    ジョブ  バッチ階層の最上位要素  複数のステップを組み合わせてジョブを構成する  ステップ全体に関わる設定はジョブに定義する (例 : リスタート制御) Job STEP2-1 JobOperator STEP1 STEP3 STEP4 STEP2-1 JobRepository Java Batch
  • 12.
    ジョブをXMLで表現すると ジョブの識別子。 JobOperator経由で起動時に このidを指定する。 <job id="samplejob" restartable="false"> <step id="step1" next="step2" /> <step id="step2" /> </job> Java Batch
  • 13.
    ジョブをXMLで表現すると ジョブがリスタート可能か。 デフォルトはtrueのオプション属性。 (リスタートについては後述) <job id="samplejob" restartable="false"> <step id="step1" next="step2" /> <step id="step2" /> </job> Java Batch
  • 14.
    ジョブをXMLで表現すると 処理したいステップを定義。 Next属性で次のステップを指定。 (順序制御は色々種類があるので、後で詳しく解説) <job id="samplejob" restartable="false"> <step id="step1" next="step2" /> <step id="step2" /> </job> Java Batch
  • 15.
    ジョブインスタンスの考え方  JobInstance 1日1回のジョブであれば、毎日1つずつ生成される。 次の日にリスタートする場合は、前日のインスタンスを使う。  JobExecution 実行ごとに生成される。リスタート時には新たに生成される。 Job 『ファイル取り込み』ジョブ * JobInstance 2007/05/05 に実行する JobInstance 『ファイル取り込み』ジョブ * JobExecution 2007/05/05 に実行する JobExecution 『ファイル取り込み』ジョブ の1回目 Java Batch
  • 16.
    ジョブとリスタート  1つのジョブインスタンスは、データとの対応を持つ  例えば、1月1日のジョブインスタンスは、1月2日に リスタートしても1月1日分のデータにアクセスする。  対象データが違うため、前日のリスタートジョブと 当日のジョブは並行実行することも可能。 1月1日分のジョブ JobInstance 実行 1/1のデータ ◎ 回目の 1/1 1 * 行 1/2のデータ △ タ ート実 1/2 リス /1分 1/3のデータ × ート時も1 JobExecution JobExecution リスタ タを処理 のデー 実行インスタンスは 実行毎に生成 Java Batch
  • 17.
    ステップ  ジョブに含まれるタスクを定義する。  各ステップの内容は、ユーザがコーディングする。  図のように、条件によって分岐することもできる。 Job STEP2-1 JobOperator STEP1 STEP3 STEP4 STEP2-1 JobRepository Java Batch
  • 18.
    ステップ : 2つの処理方式  Chunk 方式  Batchlet方式 Item STEP ItemReader Processor ItemWriter STEP batchlet execute() execute() read() process() item process(item) item writer(item) ExitStatus ExitStatus ExitStatus Chunk方式 Batchlet方式 Java Batch
  • 19.
    Chunk方式  大規模なデータ処理に適した処理方式  1件ずつ読み込んで処理するのでメモリ消費を抑える  コミット間隔の調整もしやすい Item STEP ItemReader Processor ItemWriter execute() read() Chunk = 出力の塊 を示す item process(item) 複数レコードを処理して一度に 出力することも可能である。 item (詳細は次スライドで紹介) writer(item) ExitStatus Java Batch
  • 20.
    Chunk方式 : まとめてコミット オーバヘッド低減のため、書き込みはまとめることも可能。 (chunk-size属性の設定) Item STEP ItemReader Processor ItemWriter execute() read() item process(item) 1アイテム目の読み込みと処理 item read() item process(item) 2アイテム目の読み込みと処理 item writer(items) 処理が終わった2アイテムを ExitStatus 書き込み、コミット Java Batch
  • 21.
    Chunk方式 : アノテーション Reader/Processor/Writerはユーザがコード作成する。 ItemReader のコード例 @Named public class MyItemReader { @ReadItem MyBatchInputRecord read() throws Exception { // レコード読み取り処理 } } SpringBatchはインタフェースをベースに作成するが、 JavaBatchでは、@ReadItemのようにアノテーション対応。 Java Batch
  • 22.
    Chunk方式 : CDIとの連携 JavaBatchではSpringDIの代わりにCDIが使われる ItemReader のコード例 @Named public class MyItemReader { @ReadItem MyBatchInputRecord read() throws Exception { // レコード読み取り処理 } } 全てのコンポーネントに、@java.inject.Namedが必要。 ジョブXMLからコンポーネント名を指定するため。 Java Batch
  • 23.
    Chunk方式 : ジョブXML例  ステップの子要素としてchunkを定義する  reader/processor/writer属性にはクラス名を定義  チャンクサイズの設定もXMLで可能 (デフォルトは10) <job id="samplejob" restartable="false"> <step id="step1" next="step2" > <chunk reader="MyReader" processor="MyProcessor" writer="MyWriter" chunk-size="2" /> </step> <step id="step2" /> </job> Java Batch
  • 24.
    Batchlet方式  ファイル/DB処理ではないステップに使う  ファイル圧縮・転送・各種OSコマンドの実行 など  Spring Batchのtaskletを同等のもの STEP batchlet execute() process() Chunkと比べて非常にシンプル。 STEPとbatchletが1対1となる。 ExitStatus ExitStatus Java Batch
  • 25.
    Batchlet方式 : @Process @Processを付けたメソッドに処理を記述するだけ @Named public class MyBatchLet{ @Process String process() throws Exception {...} @Stop void stopMe() throws Exception {...} } @Process  バッチレットの処理内容を定義する @Stop  JobOperator#stop()されたときにコールバックされる Java Batch
  • 26.
    Batchlet方式 : ジョブXML例  ステップの子要素としてbatchletを定義する  batchletを実装したクラス名を参照先として設定する <job id="samplejob" restartable="false"> <step id="step1" next="step2" /> <batchlet ref="MyBatchlet" /> </step> <step id="step2" /> </job> Java Batch
  • 27.
    リスナ : ジョブ・ステップ実行前後にコールバック  ジョブやステップの実行前後に呼び出される  一時ディレクトリ掃除・再生成などの前準備に使える  複数のリスナを定義することが可能 ジョブレベルリスナ ジョブレベルリスナ (ジョブ実行前) (ジョブ実行後) Job listener listener STEP2-1 listener listener STEP1 STEP3 STEP4 STEP2-1 ステップレベルリスナ (ジョブ実行前後) Java Batch
  • 28.
    JobOperator  ジョブはジョブオペレータにより起動/再起動/停止される  バッチ処理のコントロール役 Job STEP2-1 JobOperator STEP1 STEP3 STEP4 STEP2-1 JobRepository Java Batch
  • 29.
    JobOperator : API  BatchRuntimeクラスからインスタンスは取得できる  先ほどXMLで指定したジョブIDを起動のキーとする // factoryでインスタンスを取得 JobOperator jobOperator = BatchRuntime.getJobOperator(); // ジョブIDを指定して、ジョブを起動 jobOperator.start("jobid1", property); <job id="jobid1"> Java Batch
  • 30.
    JobRepository  ジョブやステップの実行状態を保存する  保存された状態にはJobOperator経由でアクセスする  前述した、リトライ用のジョブインスタンスはここに保存 Job STEP2-1 JobOperator STEP1 STEP3 STEP4 STEP2-1 JobRepository Java Batch
  • 31.
    実行順序の制御 7 Java EE Java Batch
  • 32.
    ステップ実行手順は複数の手段がある  Flow - ステップのグループ化  Sprit – 並行実行するフローの組み合わせを定義  Decision – ステップの終了ステータスに応じた条件分岐 start STEP1 Flow (ステップ グループ化) STEP2-1 STEP2-2 end STEP3-1 Decision(条件分岐) Flow split Flow Flow split (ステップの並行実行) Java Batch
  • 33.
    もっともシンプルなケース 1つのジョブに、ステップが順処理で2つ start end STEP1 STEP2 next属性に次ステップを指定。 idが対象。 <job id="samplejob"> <step id="step1" next="step2" /> <step id="step2" /> </job> Java Batch
  • 34.
    Flow  ステップを一連のユニットとしてまとめる  フローが終了したあとは、次エレメントに遷移 (ステップ、スプリット、デシジョン、他のフローのいずれか) start Flow end STEP1 STEP2-1 STEP2-1 STEP3 <job id="samplejob"> <step id="step1"> <flow id="flow1" next="step3"> フローの中に複数ステップを定義。 <step id="step2-1"/> <step id="step2-2"/> next属性には、フローが完了した </flow> あとの次のステップを定義する。 <step id="step3" /> </job> Java Batch
  • 35.
    Split : 3つの構成要素  Split : 並列実行するフローの組み合わせを定義  Split Collector :  フロー実行結果を受け取り Split Analyzer に送る。  Split Analyzer :  Split Collectorから受け取った並行実行結果を処理する。 Flow Split Collector start end split split Flow Split Collector STEP2 analyzer Flow Split Collector Java Batch
  • 36.
    Split : ジョブXMLの書き方  スプリットの中に並列実行したいフローを定義する  各フローは別々のスレッドで実行される <job id="samplejob"> <split id="split1" next="step2"> <flow id="flow1"> <step id="step1-1-1" next="step1-1-2"/> <step id="step1-1-2"/> </flow> <flow id="flow2"> <step id="step1-2-1" next="step1-2-2"/> <step id="step1-2-2"/> </flow> </split> <step id="step2" /> </job> Java Batch
  • 37.
    Split Collector  フロー結果をスプリットアナライザに中継する役割  各スプリットしたフローの実行スレッドで動作  FlowContextからデータを集め、Externalizableで返す FlowContextで 受け渡し Externalizableで 受け渡し Flow Split Collector start end split split Flow Split Collector STEP2 analyzer Flow Split Collector Java Batch
  • 38.
    Split Collector :@CollectSplitData @Named コンテキストは自動的に public class SplitCollector { インジェクションされる @BatchContext FlowContext flowContext; Split Collector を示すアノテーション @CollectSplitData Externalizable collectSplitData() throws Exception { // コンテキストからFlowデータの取得 FlowData flowData = flowContext.getTransientUserData(); // Externalizable実装のユーザクラスを生成 ExternalizableBookData serial = new ExternalizableBookData(); serial.setName(flowData.getBookName()); // Externalizableを返す return serial; } 外部化(Externalizable)の結果を返す } Memo. 仕様書には『The FlowContext is in scope when this method receives control.』とあるが、 Split Collectorがどうやって各スプリットの結果を受け取るかはうまく読み取れていない。 読み取れる範囲からは、上記のようにコンテキストからデータ取得すると思われる。 Java Batch
  • 39.
    参考 : java.io.Externalizable  Serializableを継承したインタフェース  オブジェクトの外部出力を自分でコーディングする。 public class Book implements Externalizable { String title; int price; 引数なしコンストラクタを忘れると 復元時に InvalidClassException が public Book() {} 投げられるので注意。 public Book(String title, int price) { this.title = title; this.price = price; } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF(title); out.writeInt(price); } 書き出し処理 @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { title = in.readUTF(); price = in.readInt(); } 復元処理 } Java Batch
  • 40.
    Split Analyzer  Split Collectorから並行実行したフロー結果を集約する。  Collectorと異なり、シングルスレッドで動作する。  Collectorからデータが送られるたびに複数回起動する。 Split Collectorから 各フロー結果を受け取る Flow Split Collector start end split split Flow Split Collector STEP2 analyzer Flow Split Collector 集約・分析結果を出力 ファイル DBMS Java Batch
  • 41.
    Split Analyzer :@AnalyzeCollectorData @Named SplitContextにアクセスできる public class SplitAnalyzer { @BatchContext Collectorから受け取ったデータを分析。 SplitContext splitContext; Collectorが書き出し回数分繰り返し呼ばれる。 (3スプリットであれば、3回呼ばれる) @AnalyzeCollectorData void analyze(Externalizable data) throws Exception{ // SplitCollectorから受け取ったデータを分析 } バッチステータスやスプリットの終了コードに @AnalyzeStatus 応じた処理を定義する。 void analyzeStatus(String batchStatus, String exitStatus) throws Exception { // スプリットの終了ステータスに応じた処理を行う } } Memo. 仕様書には『The analyzeCollectorData method receives control each time a Partition collector sends its payload.』と書かれていて、この解釈をCollectorからデータが送られるたびに毎回起動されると解釈した。 一方、Analyzerはシングルスレッド起動としても明記されているため、一度に複数のCollectorからデータが送られた 場合の挙動が仕様書からはうまく読み取れていない。 Java Batch
  • 42.
    CollectorとAnalyzer : ジョブXMLの書き方 <jobid="samplejob"> <split id="split1" next="step2"> <flow id="flow1"> <step id="step1-1-1" next="step1-1-2"/> <step id="step1-1-2"/> </flow> <flow id="flow2"> <step id="step1-2-1" next="step1-2-2"/> <step id="step1-2-2"/> </flow> <collector ref="SplitCollector" /> <analyzer ref="SplitAnalyzer" /> </split> Splitエレメントの子エレメントとして定義。 <step id="step2" /> 参照先の実装クラス名をrefに指定する。 </job> Java Batch
  • 43.
    Decision  ステップ・フロー・スプリットの終了ステータスをもとに 次の遷移先を選択する。  全部で4種類の遷移を指定できる <next> : 次エレメントへ遷移 <end> : 正常終了 <fail> : 異常終了 <stop> : 一時停止 <next on=”*” to=”STEP2”> STEP2 start Decision <end on=”stop step”> STEP1 exit status end <fail on=”fail step”> × 異常終了 Java Batch
  • 44.
    バッチステータス と 終了ステータス  バッチステータス  ジョブ全体の現在の状態を定義するパラメータ  状態の種類は仕様で定義されている  バッチランタイムにより設定される  終了ステータス Desicionの判定対象  ジョブ・ステップ・フロー・スプリットの終了ステータス  文字列値をユーザで定義する  ユーザが設定する。 何も設定されていない場合は、バッチステータスと同じ値。 Step Step exit status exit status start end Job exit status STEP1 STEP2 Batch Status (バッチ全体の現在の状態) Java Batch
  • 45.
    終了ステータスの設定方法  コンテキストのAPIで設定する  リスナーで設定すると、Chunk処理と分離できて便利 @Named public class StepListener { @BatchContext StepContext stepContext; @BeforeStep public void beforeStep() throws Exception { // なんらかの前処理をする } Stepから特定の例外が投げられた場合に 終了ステータスを設定する。 @AfterStep public void afterStep() throws Exception { if (stepContext.getException() instanceof InvalidRecordException) { stepContext.setExitStatus("failed cause invalid records"); } } } Memo. 仕様書にはリスナのコンテキストについて言及されていない。ステップ・リスナにはステップ・コンテキストが インジェクションできると思うが、上記のコードは推測の域である。 Java Batch
  • 46.
    参考 : バッチステータス一覧 ステータス値 意味 バッチジョブは、ジョブオペレータのでスタートまたはリスタート操作されると、バッチ STARTING ランタイムによりSTARTING状態とされます。 ステップにおいても、実行開始直前はSTARTING状態となります。 バッチジョブがバッチランタイムにより既に開始されている状態です。 STARTED ステップにおいても、一度実行された後はSTARTED状態となります。 バッチジョブが、ジョブオペレータの停止操作、またはジョブXMLの<stop>エレメントに STOPPING よって停止要求された状態です。ステップにおいても、STOPPING状態となった場合は、 バッチランタイムによりまもなく停止処理が行われます。 バッチジョブが、ジョブオペレータの停止操作、またはジョブXMLの<stop>エレメントに STOPPED よって停止した状態です。ステップにおいても、バッチランタイムに停止された場 合、STOPPED状態となります。 バッチジョブが、未解決の例外、またはジョブXMLの<fail>エレメントによって終了した FAILED 状態です。ステップにおいても同様の条件でFAILED状態となります。 バッチジョブが、正常終了、またはジョブXMLの<end>エレメントによって終了した状態 COMPLETED です。ステップにおいても同様の条件でCOMPLETED状態となります。 バッチジョブが、ジョブオペレータの『放棄(avandoned)』操作が行われたことを示す状 ABANDONED 態です。放棄状態のジョブはジョブオペレータ経由で確認することはできますが、実行や リスタートを行うことはできません。履歴閲覧を目的に確認できるようになっています。 Java Batch
  • 47.
    Decision : @Decide  メソッド引数でコンテキストを取得する  終了コードを判定し、条件に応じて終了コードを上書き 終了コードが SUCCESS の場合、 @Named SKIP に上書きする。 public class Decider { @Decide public String decide(BatchContext context) throws Exception { String exitStatus = context.getExitStatus(); if ("SUCCESS".equals(exitStatus)) { return "SKIP"; } return exitStatus; } } Java Batch
  • 48.
    Decision : ジョブXMLの書き方 Decisionではスキップの決定など動的な遷移制御ができる。 refにはDeciderのクラス名を設定 <job id="samplejob"> <step id="step1"> <decision id="decision1" ref="Decisider"> <next on="SKIP" to="step3"/> <next on="*" to="step2"/> </decision> </step> <step id="step2" next="step3"/> DeciderからSKIPが返された場合は step3に進む。 <step id="step3"> </job> それ以外はstep2に進む。 Java Batch
  • 49.
    実行順序の制御 : まとめ  ジョブXMLとAPIを駆使して、様々な遷移が可能  主な手段として Flow、Decision、Split の3種類がある。 start STEP1 Flow (ステップ グループ化) STEP2-1 STEP2-2 end STEP3-1 Decision(条件分岐) Flow split Flow Flow split (ステップの並行実行) Java Batch
  • 50.
    例外ハンドリング 7 Java EE Java Batch
  • 51.
    バッチ失敗の原因 : 不正なレコード 不正なレコートが1行あっただけで、バッチ全体が失敗する バッチプログラム 処理対象のファイル Name, Age, Address SUCCESS 山田, 29, 千葉 SUCCESS 佐藤, 46, 埼玉 SUCCESS (数万行続く...) ... FAIL 破壊,,aaa,,99,,, Status FAIL Java Batch
  • 52.
    バッチ失敗の原因 : 一時的に繋がらない DBセッションが一時的に足りないだけで、翌日に再実行。 100 Session ジョブA Max Session = 200 90 Session × ジョブB 一時的な過負荷により DBセッション数が足りない ジョブC Java Batch
  • 53.
    バッチ失敗の原因 : パーミッションがない ディレクトリや一時ファイルの作成に失敗する。 一般ユーザ 拒否 × 一時ファイル root権限のディレクトリ バッチプログラム (一般ユーザ) mk di r グループ書き込み権が × 足りない パーミッション744の ディレクトリ Java Batch
  • 54.
    Java Batch 3つのエラーハンドリング  スキップ  不正な入力データをスキップして、処理を継続 Chunk方式のステップが対象   リトライ  一時的な要因により失敗した処理を再実行  セッション不足、ロック待ち など  リスタート  深刻なエラーが発生した場合はジョブを失敗させる  原因を取り除き、手動で再起動する Java Batch
  • 55.
    スキップ  JavaBatchには次レコードにスキップしても良い例外を登録 (ジョブXMLに例外クラス名を記述)  ItemReaderから投げられた例外がスキップ対象か判定する。  デフォルトは例外が1つでも発生すると、ジョブは失敗する JavaBatchランタイム Chunk方式 2.例外スロー Name, Age, Address スキップ対象例外 ItemReader 1. 例外 発生 山田, 29, 千葉 InvaliedRecordException 3.スキップ許可 破壊,,aaa,,99,,, xxx Exception 佐藤, 54, 埼玉 △△△ Exception 4. スキップ Item 田中, 25, 東京 Processor 不正レコードを含んだ Item 入力ファイル Writer Java Batch
  • 56.
    スキップ : <skippable-exception-classes> <jobid="samplejob" restartable="false"> スキップ上限数を設定 <step id="step1" next="step2" > <chunk reader="MyReader" processor="MyProcessor" writer="MyWriter" skip-limit="10"> <skippable-exception-classes> <include class="java.io.IOException" /> <exclude class="java.net.SocketException" /> </skippable-exception-classes> </chunk> スキップ対象の例外を設定。 </step> 子クラスも対象になるので、 <step id="step2" /> excludeで除外対象も要指定。 </job> デフォルトは1つでも例外発生した時点でジョブ失敗。 必ずスキップ対象例外を設定すること。 ファイル全体が不正なものに備えて、スキップ上限数も必ず設定する。 Java Batch
  • 57.
    スキップリスナ : @OnSkipedReadItem  どのレコードをスキップしたのか記録することは重要  スキップ契機のリスナーであるスキップリスナでロギング @Named public class SkipListener { private static final Logger logger = Logger.getLogger(SkipListener.class); @OnSkipReadItem public void onSkipReadItem(Exception ex) throws Exception { // エラーメッセージのロギング logger.log(ex.getMessage()); } } Java Batch
  • 58.
    スキップリスナ : ジョブXMLの書き方 <jobid="samplejob" restartable="false"> <step id="step1" next="step2" > <chunk reader="MyReader" processor="MyProcessor" writer="MyWriter" skip-limit="10"> <skippable-exception-classes> <include class="java.io.IOException" /> <exclude class="java.net.SocketException" /> </skippable-exception-classes> </chunk> <listeners> <listener ref="SkipListener" /> </listeners> </step> <step id="step2" /> スキップリスナはステップ階層の </job> リスナとして登録する。 ref属性にはクラス名を指定。 Java Batch
  • 59.
    ItemProcessorで例外が発生したら?  チャンクサイズ分、まとめて読み込まれる。  例外発生するとチャンク全体をロールバック。  読み込み済キャッシュは再利用される。 ロールバック chunk size分読み込み <chunk chunk-size=”x”> Cash Item Process Read Item Read Item Cash Item Process Write Item Read Item Cash Item Process トランザクション区間 Java Batch
  • 60.
    ItemProcessor例外 : スキップ方法  キャッシュからアイテムをロードして再処理  例外の原因となったアイテムはスキップする キャッシュからロード Cash Item Process Read Item Read Item Cash Item スキップ Write Item Read Item Cash Item Process トランザクション区間 ▲ commit Java Batch
  • 61.
    ItemWriterで例外が発生したら?  Writerは処理したデータをまとめて受け取る  どの入力がエラーの原因になったのかわからない → スキップ対象のItemを特定しにくいのが特徴 ロールバック ? Cash Item Process Read Item Cash Item ? Process Write Item Read Item Read Item ? Cash Item Process @WriteItems writeItems(List<T> items); Java Batch
  • 62.
    ItemWriter例外 : スキップ方法  1アイテムずつキャッシュから読み込み処理  例外が発生したアイテムをスキップする → Processorと異なり、再度例外発生させてスキップ Cash Item Process Write Item 1アイテムずつトランザクションを分ける ▲ commit Read Item Read Item Read Item Cash Item Process Write Item × 例外アイテム スキップ Cash Item Process Write Item ▲ commit Java Batch
  • 63.
    リトライ  一時的な原因の例外に対して効果的 (ネットワーク不安定/DBロック待ち など)  リトライを繰り返すと、性能に影響を与えるので注意  チャンク単位でリトライする インターネット Cash Item Process Read Item Read Item Read Item Cash Item Process Write Item × Cash Item Process 接続失敗 チャンク単位でリトライ Web Cash Item Process 成功 Service Cash Item Process Write Item Cash Item Process 外部のWebサービスは繋がりにくい場合もあるので、リトライが効果的 Java Batch
  • 64.
    リトライ : <retryable-exception-classes> <jobid="samplejob" restartable="false"> リトライ回数を設定 <step id="step1" next="step2" > <chunk reader="MyReader" processor="MyProcessor" writer="MyWriter" retry-limit="3"> <retryable-exception-classes> <include class="javax.xml.ws.soap.SOAPFaultException" /> <exclude class="xxxException" /> </retryable-exception-classes> </chunk> リトライ対象の例外を設定。 </step> 子クラスも対象になるので、 <step id="step2" /> excludeで除外対象も要指定。 </job> retry-limitを設定しない場合、デフォルトではリトライし続ける。 必ずretry-limitに値を設定すること。 Java Batch
  • 65.
    リトライリスナ : @OnRetryWriteException  スキップと同様に、リトライもロギングが重要  リトライリスナをユーザが実装してロギングする @Named public class RetryListener { private static final Logger logger = Logger.getLogger(RetryListener.class); @OnRetryWriteException public void onRetryWriteException(List<T> items,Exception ex) throws Exception { // エラーメッセージのロギング logger.log(ex.getMessage()); } } Java Batch
  • 66.
    リトライリスナ : ジョブXMLの書き方 <jobid="samplejob" restartable="false"> <step id="step1" next="step2" > <chunk reader="MyReader" processor="MyProcessor" writer="MyWriter" skip-limit="10"> <retryable-exception-classes> <include class="javax.xml.ws.soap.SOAPFaultException" /> <exclude class="xxxException" /> </retryable-exception-classes> </chunk> <listeners> <listener ref="RetryListener" /> </listeners> </step> <step id="step2" /> リトライリスナはステップ階層の </job> リスナとして登録する。 ref属性にはクラス名を指定。 Java Batch
  • 67.
    リトライとスキップを組み合わせる  リトライとスキップは通常組み合わせて設定する  例: 3回リトライして、失敗する場合は10回までスキップ <job id="samplejob" restartable="false"> リトライ回数 スキップ上限数 <step id="step1" next="step2" > <chunk reader="MyReader" processor="MyProcessor" writer="MyWriter" retry-limit="3" skip-limit="10"> <retryable-exception-classes> <include class="javax.xml.ws.soap.SOAPFaultException" /> </retryable-exception-classes> <skippable-exception-classes> <include class="javax.xml.ws.soap.SOAPFaultException" /> </skippable-exception-classes> </chunk> </step> <step id="step2" /> 同じ例外をretryable-exception-classesと </job> skippable-exception-classesに設定する Java Batch
  • 68.
    リスタート  失敗したステップから再開する機能  スキップやリトライで対処できない問題に対応 (オペレータが手を入れないと治らない問題)  チャンク処理内でのリスタートも可能 × ディスクフル発生 STEP1 STEP2 STEP3 STEP4 対向システムから 解凍 集計処理 次システムへ ファイル取得 集計データ転送 リスタート STEP3 STEP4 (STEP3から再開) 集計処理 次システムへ 集計データ転送 Java Batch
  • 69.
    allow-start-if-complete の設定  業務によっては、ステップを1からやり直したい  ジョブXMLへの設定で、ステップが完了していた場合に 再実行するか設定ができる 途中から再開(デフォルト) 最初から再開 STEP1 STEP1 STEP2 STEP2 STEP3 STEP3 <step id="step1" <step id="step1" allow-start-if-complete="true"> allow-start-if-complete="false"> Java Batch
  • 70.
    リスタート : ジョブXML restartable属性 : ジョブごとにリスタート可能か設定  Start-limit属性 : ステップごとにリスタート上限数を設定 リスタート可能か? (オプション。デフォルトtrue) <job id="samplejob" restartable="true"> <step id="step1" next="step2" start-limit="5" /> リスタート上限回数 <step id="step2" next="step3" allow-start-if-complete="false"/> <step id="step3" /> </job> 完了していても再実行時に動かすか Java Batch
  • 71.
    エラーハンドリングのポイント いかに『堅牢なバッチ』を作るかがポイント  堅牢とは  少々のエラーデータが混じっていても落ちない  一時的なエラーであれば自動的に復旧  オペレータの手をかけないバッチが堅牢なバッチ  Java Batch が提供する手段  スキップ : 不正データのスキップ  リトライ : 一時的なエラーに対する自動再試行  リスタート : 途中から再開することで、再実行コスト低減 Java Batch
  • 72.
    あとがき 7 Java EE Java Batch
  • 73.
    2013年上半期に仕様はfinalへ  Public Reviewをもとに調査した  2013/1 現在は前述した仕様群は作業中  仕様確定に向けて、まだ内容は修正される可能性も  Java EE 7 へ盛り込みへ  次のJava EE 仕様である『7』に盛り込まれる予定  Java EE 7 も2013年内にはリリース予定  EE 7 - GlashFishリリースまで、SpringBatchとの差分調査は難しい Javaで大規模バッチ構築のために、期待する標準です。 Java Batch