2.9. ルートの起動およびシャットダウンの制御
概要
デフォルトでは、Apache Camel アプリケーション (CamelContext
インスタンスで表される) の起動時にルートが自動的に起動し、Apache Camel アプリケーションのシャットダウン時にルートは自動的にシャットダウンします。クリティカルでないデプロイメントは、シャットダウン順序の詳細は通常それほど重要ではありません。しかし、本番環境では、データ損失を回避するために、シャットダウン時に残っているタスクを完了させることが重要になります。また、通常、依存関係の順序違反 (実行中のタスクが完了できなくなる) を防止するために、ルートがシャットダウンする順番を制御したくなることもあります。
このため、Apache Camel はアプリケーションの 正常なシャットダウン をサポートする機能を提供しています。正常なシャットダウンにより、ルートの停止と起動を完全に制御し、ルートのシャットダウン順序を制御し、現在実行中のタスクを完了まで実行できるようになります。
ルート ID の設定
ルート ID を各ルートに割り当てるのが良いプラクティスです。ルート ID を設定すると、ロギングメッセージや管理機能がよりわかりやすくなるだけでなく、ルートの停止と起動の制御がより行いやすくなります。
たとえば、Java DSL では、以下のように routeId()
コマンドを実行して、ルート ID myCustomerRouteId
をルートに割り当てることができます。
from("SourceURI").routeId("myCustomRouteId").process(...).to(TargetURI);
XML DSL では、以下のように route
要素の id
属性を設定します。
<camelContext id="CamelContextID" xmlns="http://camel.apache.org/schema/spring"> <route id="myCustomRouteId" > <from uri="SourceURI"/> <process ref="someProcessorId"/> <to uri="TargetURI"/> </route> </camelContext>
ルートの自動起動の無効化
デフォルトでは、起動時に CamelContext が認識しているすべてのルートは自動的に起動されます。しかし、特定のルートの起動を手動で制御する場合は、そのルートの自動起動を無効にできます。
Java DSL ルートが自動的に起動するかどうかを制御するには、boolean
引数 (true
または false
) か、String
引数 (true
または false
) のいずれかで、autoStartup
コマンドを呼び出します。たとえば、以下のように Java DSL でルートの自動起動を無効にできます。
from("SourceURI") .routeId("nonAuto") .autoStartup(false) .to(TargetURI);
XML DSL では、以下のように route
要素の autoStartup
属性を false
に設定して、ルートの自動起動を無効にできます。
<camelContext id="CamelContextID" xmlns="http://camel.apache.org/schema/spring"> <route id="nonAuto" autoStartup="false"> <from uri="SourceURI"/> <to uri="TargetURI"/> </route> </camelContext>
手動によるルートの起動および停止
Java において、CamelContext
インスタンスの startRoute()
および stopRoute()
メソッドを呼び出すことにより、ルートを手動でいつでも起動または停止できます。たとえば、ルート ID nonAuto
を持つルートを開始するには、以下のように CamelContext
インスタンス context
で startRoute()
メソッドを呼び出します。
// Java context.startRoute("nonAuto");
ルート ID nonAuto
を持つルートを停止するには、以下のように CamelContext
インスタンス context
で stopRoute()
メソッドを呼び出します。
// Java context.stopRoute("nonAuto");
ルートの起動順序
デフォルトでは、Apache Camel はルートを非決定論的な順序で起動します。しかし、アプリケーションによっては、起動順序を制御することが重要になる場合があります。Java DSL で起動順序を制御するには、startupOrder()
コマンドを使用します。このコマンドは、正の整数値を引数として取ります。整数値が最も小さいルートが最初に起動し、それ以降、起動順序の値が小さいものから順番にルートが起動します。
たとえば、以下の例では最初の 2 つのルートが seda:buffer
エンドポイントを通して繋ぎ合わされています。以下のように起動順序 (それぞれ 2 と 1) を割り当てることで、最初のルートセグメントを 2 つ目のルートセグメントの 後に 起動させることができます。
例2.5 Java DSL の起動順序
from("jetty:http://fooserver:8080") .routeId("first") .startupOrder(2) .to("seda:buffer"); from("seda:buffer") .routeId("second") .startupOrder(1) .to("mock:result"); // This route's startup order is unspecified from("jms:queue:foo").to("jms:queue:bar");
または、Spring XML では、以下のように route
要素の startupOrder
属性を設定することで、同様の効果を得ることができます。
例2.6 XML DSL の起動順序
<route id="first" startupOrder="2"> <from uri="jetty:http://fooserver:8080"/> <to uri="seda:buffer"/> </route> <route id="second" startupOrder="1"> <from uri="seda:buffer"/> <to uri="mock:result"/> </route> <!-- This route's startup order is unspecified --> <route> <from uri="jms:queue:foo"/> <to uri="jms:queue:bar"/> </route>
各ルートには、一意 の起動順序の値を割り当てる必要があります。値は 1000 未満の正の整数から選択できます。1000 以上の値は Apache Camel 用に予約されており、明示的な起動値を持たないルートにこれらの値が自動的に割り当てられます。たとえば、前述の例の最後のルートは自動的に起動値 1000 が割り当てられます (これにより最初の 2 つのルートの後に起動することになります)。
シャットダウンシーケンス
CamelContext
インスタンスがシャットダウンしているとき、Apache Camel はプラグ可能な シャットダウンストラテジー を使用してシャットダウンシーケンスを制御します。デフォルトのシャットダウンストラテジーは、以下のシャットダウンシーケンスを実装します。
- ルートが起動順序の 逆順 でシャットダウンされる。
- 通常、シャットダウンストラテジーは、現在アクティブなエクスチェンジの処理が終了するまで待機する。ただし、実行中タスクの取り扱いは設定可能。
- 全体的なシャットダウンシーケンスには、タイムアウトの上限がある (デフォルトは 300 秒)。シャットダウンシーケンスがこのタイムアウトを超えると、シャットダウンストラテジーは、一部のタスクが実行中であっても強制的にシャットダウンを実行する。
ルートのシャットダウン順序
ルートは起動順序の逆順でシャットダウンされます。つまり、起動順序が startupOrder()
コマンド (Java DSL) または startupOrder
属性 (XML DSL) を使用して定義されている場合、最初にシャットダウンするルートは、起動順として割り当てられた 最大 の整数値を持つルートであり、最後にシャットダウンするルートは、起動順として割り当てられた 最小 の整数値を持つルートになります。
たとえば、例2.5「Java DSL の起動順序」 では、最初にシャットダウンするルートセグメントは ID first
のルートで、2 番目にシャットダウンするルートセグメントは ID second
のルートになります。この例は、ルートをシャットダウンする際に守るべき一般的なルールを示しています。つまり、外部からアクセス可能なコンシューマーエンドポイントを公開するルートは最初にシャットダウンする必要がある、ということです。これは、残りのルートグラフを流通するメッセージのフローを調整するスロットルとなるためです。
Apache Camel は、オプション shutdownRoute(Defer)
も提供しています。これにより、ルートを (起動順の値を上書きして) 最後にシャットダウンするように指定できます。ただし、このオプションが必要になることはほとんどありません。このオプションは主に、ルートが起動順序と 同じ 順序でシャットダウンしていた Apache Camel の以前のバージョン (2.3 以前) への回避策として必要だったものです。
ルート内で実行中のタスクのシャットダウン
シャットダウンの開始時にルートが依然としてメッセージを処理している場合、シャットダウンストラテジーは通常、現在アクティブなエクスチェンジの処理が終了するまで待機してからルートをシャットダウンします。この動作は、ルート毎に shutdownRunningTask
オプションを使用することで設定できます。このオプションは以下のいずれかの値を取ります。
ShutdownRunningTask.CompleteCurrentTaskOnly
- (デフォルト) 通常、ルートは一度に 1 つのメッセージのみを処理するため、現在のタスクが完了した後にルートを安全にシャットダウンできます。
ShutdownRunningTask.CompleteAllTasks
- バッチコンシューマー を正常にシャットダウンするには、このオプションを指定します。一部のコンシューマーエンドポイント (File、FTP、Mail、iBATIS、JPA など) は一度に複数のメッセージを一括して処理します。これらのエンドポイントでは、現在のバッチのすべてのメッセージが完了するまで待機することが推奨されます。
たとえば、File コンシューマーエンドポイントを正常にシャットダウンするには、以下の Java DSL フラグメントのように CompleteAllTasks
オプションを指定する必要があります。
// Java
public void configure() throws Exception {
from("file:target/pending")
.routeId("first").startupOrder(2)
.shutdownRunningTask(ShutdownRunningTask.CompleteAllTasks)
.delay(1000).to("seda:foo");
from("seda:foo")
.routeId("second").startupOrder(1)
.to("mock:bar");
}
同じルートを XML DSL では以下のように定義できます。
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<!-- let this route complete all its pending messages when asked to shut down -->
<route id="first"
startupOrder="2"
shutdownRunningTask="CompleteAllTasks">
<from uri="file:target/pending"/>
<delay><constant>1000</constant></delay>
<to uri="seda:foo"/>
</route>
<route id="second" startupOrder="1">
<from uri="seda:foo"/>
<to uri="mock:bar"/>
</route>
</camelContext>
シャットダウンのタイムアウト
シャットダウンタイムアウトのデフォルト値は 300 秒です。シャットダウンストラテジーの setTimeout()
メソッドを呼び出すことで、タイムアウトの値を変更できます。たとえば、以下のようにタイムアウト値を 600 秒に変更できます。
// Java // context = CamelContext instance context.getShutdownStrategy().setTimeout(600);
カスタムコンポーネントとの統合
カスタムの Apache Camel コンポーネント (同じく org.apache.camel.Service
インターフェイスから継承する) を実装している場合、org.apache.camel.spi.ShutdownPrepared
インターフェイスを実装することで、カスタムコードがシャットダウン通知を受け取るようにすることができます。これにより、コンポーネントはシャットダウンに備えてカスタムコードを実行できるようになります。
2.9.1. RouteIdFactory
コンシューマーエンドポイントに基づいて、ルート ID に論理名を割り当てられる RouteIdFactory
を追加することができます。
たとえば、seda または direct コンポーネントをルートの入力として持つルートを使用するとき、以下のようにそれらの名前をルート ID として使用する場合があります。
- direct:foo - foo
- seda:bar - bar
- jms:orders - orders
自動的に割り当てられた名前を使用する代わりに、NodeIdFactory
を用いてルートに論理名を割り当てることができます。また、ルート URL の context-path を名前として使用することもできます。たとえば、以下を実行して RouteIDFactory
を使用します。
context.setNodeIdFactory(new RouteIdFactory());
REST エンドポイントからカスタムルート ID を取得することもできます。