機能

このセクションでは、Spring Cloud Task の使用方法、設定方法、適切な拡張ポイントなど、Spring Cloud Task について詳しく説明します。

Spring Cloud Task のライフサイクル

ほとんどの場合、最新のクラウド環境は、終了が予想されないプロセスの実行を中心に設計されています。終了した場合、通常は再起動されます。ほとんどのプラットフォームには、終了時に再起動されないプロセスを実行する何らかの方法がありますが、通常、その実行結果は消耗的な方法で維持されません。Spring Cloud Task は、環境内で短期間のプロセスを実行し、結果を記録する機能を提供します。そうすることで、メッセージによるタスクの統合を通じて、存続期間の短いプロセスだけでなく、長時間実行されるサービスを中心としたマイクロサービスアーキテクチャが可能になります。

この機能はクラウド環境では便利ですが、従来の デプロイモデルでも同じ問題が発生する可能性があります。cron などのスケジューラーを使用して Spring Boot アプリケーションを実行する場合、完了後にアプリケーションの結果を監視できると便利です。

Spring Cloud Task は、Spring Boot アプリケーションが開始と終了を持ちながらも成功できるというアプローチを採用しています。バッチアプリケーションは、終了が予想されるプロセス (多くの場合、有効期間が短い) がどのように役立つかを示す 1 つの例です。

Spring Cloud Task は、特定のタスクのライフサイクルイベントを記録します。ほとんどの Web アプリケーションに代表される、長時間実行プロセスのほとんどは、ライフサイクルイベントを保存しません。Spring Cloud Task の中心となるタスクはこれを実行します。

ライフサイクルは単一のタスクの実行で構成されます。これは、タスクとして構成された Spring Boot アプリケーションの物理的な実行です (つまり、Sprint Cloud タスクの依存関係があります)。

タスクの開始時、CommandLineRunner または ApplicationRunner 実装が実行される前に、開始イベントを記録する TaskRepository 内のエントリが作成されます。このイベントは、Spring Framework によってトリガーされる SmartLifecycle#start によってトリガーされます。これは、すべての Bean が使用できる状態にあり、Spring Boot によって提供される CommandLineRunner または ApplicationRunner 実装を実行する前に行われることをシステムに示します。

タスクの記録は、ApplicationContext のブートストラップが成功した場合にのみ行われます。コンテキストがブートストラップにまったく失敗した場合、タスクの実行は記録されません。

Spring Boot からの *Runner#run 呼び出しがすべて完了するか、ApplicationContext が失敗する ( ApplicationFailedEvent によって示される) と、タスクの実行が結果とともにリポジトリ内で更新されます。

アプリケーションがタスクの補完時に ApplicationContext を閉じる必要がある場合 (すべての *Runner#run メソッドが呼び出され、タスクリポジトリが更新されている場合)、プロパティ spring.cloud.task.closecontextEnabled を true に設定します。

TaskExecution

TaskRepository に格納される情報は TaskExecution クラスでモデル化され、次の情報で構成されます。

フィールド 説明

executionid

タスクの実行の一意の ID。

exitCode

ExitCodeExceptionMapper 実装から生成された終了コード。終了コードは生成されないが、ApplicationFailedEvent がスローされた場合、1 が設定されます。それ以外の場合は、0 とみなされます。

taskName

構成された TaskNameResolver によって決定されるタスクの名前。

startTime

SmartLifecycle#start 呼び出しによって示される、タスクが開始された時刻。

endTime

ApplicationReadyEvent で示されるタスクの補完時刻。

exitMessage

退出時に入手可能な情報。これは、TaskExecutionListener によってプログラム的に設定できます。

errorMessage

例外がタスク終了の原因である場合 ( ApplicationFailedEvent によって示される)、その例外のスタックトレースがここに保存されます。

arguments

実行可能 Boot アプリケーションに渡された文字列コマンドライン引数の List

終了コードのマッピング

タスクが完了すると、OS に終了コードを返そうとします。元の例を見ると、アプリケーションのその側面を制御していないことがわかります。例外がスローされた場合、JVM はデバッグに役立つかどうかわからないコードを返します。

そのため、Spring Boot は、キャッチされなかった例外を終了コードにマップできるインターフェース ExitCodeExceptionMapper を提供します。そうすることで、何が問題だったのかを終了コードのレベルで示すことができます。また、この方法で終了コードをマッピングすることにより、Spring Cloud Task は返された終了コードを記録します。

タスクが SIG-INT または SIG-TERM で終了する場合、コード内で特に指定されていない限り、終了コードは 0 です。

タスクの実行中、終了コードはリポジトリに null として保存されます。タスクが完了すると、このセクションで前述したガイドラインに基づいて、適切な終了コードが保存されます。

構成

Spring Cloud Task は、DefaultTaskConfigurer クラスおよび SimpleTaskConfiguration クラスで定義されているように、すぐに使用できる構成を提供します。このセクションでは、デフォルト設定と、ニーズに合わせて Spring Cloud Task をカスタマイズする方法について説明します。

データソース

Spring Cloud Task は、タスクの実行結果を保存するためにデータソースを使用します。デフォルトでは、H2 のメモリ内インスタンスを提供して、ブートストラップ開発の簡単な方法を提供します。ただし、本番環境では、おそらく独自の DataSource を構成する必要があるでしょう。

アプリケーションが単一の DataSource のみを使用し、それがビジネススキーマとタスクリポジトリの両方として機能する場合、必要なのは DataSource を提供することだけです (これを行う最も簡単な方法は、Spring Boot の構成規則を使用することです)。この DataSource は、Spring Cloud Task によってリポジトリとして自動的に使用されます。

アプリケーションが複数の DataSource を使用する場合は、適切な DataSource を使用してタスクリポジトリを構成する必要があります。このカスタマイズは、TaskConfigurer の実装を通じて実行できます。

テーブルプレフィックス

TaskRepository の変更可能なプロパティの 1 つは、タスクテーブルのテーブルプレフィックスです。デフォルトでは、すべての先頭に TASK_ が付きます。TASK_EXECUTION と TASK_EXECUTION_PARAMS が 2 つの例です。ただし、このプレフィックスを変更する潜在的な理由があります。スキーマ名をテーブル名の先頭に追加する必要がある場合、または同じスキーマ内に複数のタスクテーブルのセットが必要な場合は、テーブルのプレフィックスを変更する必要があります。これを行うには、次のように spring.cloud.task.tablePrefix を必要なプレフィックスに設定します。

spring.cloud.task.tablePrefix=yourPrefix

spring.cloud.task.tablePrefix を使用することにより、ユーザーは、タスクテーブルスキーマの条件を満たし、かつユーザーのビジネスニーズに必要な変更を加えたタスクテーブルを作成する責任を負います。ここに示すように、独自のタスク DDL を作成するときのガイドとして Spring Cloud Task スキーマ DDL を利用できます。

テーブルの初期化を有効 / 無効にする

タスクテーブルを作成していて、タスクの開始時に Spring Cloud Task にタスクテーブルを作成させたくない場合は、次のように spring.cloud.task.initialize-enabled プロパティを false に設定します。

spring.cloud.task.initialize-enabled=false

デフォルトは true です。

プロパティ spring.cloud.task.initialize.enable は非推奨になりました。

外部で生成されたタスク ID

場合によっては、タスクがリクエストされたときと、インフラストラクチャが実際にタスクを起動するときとの間の時間差を考慮したい場合があります。Spring Cloud Task を使用すると、タスクがリクエストされたときに TaskExecution を作成できます。次に、生成された TaskExecution の実行 ID をタスクに渡し、タスクのライフサイクルを通じて TaskExecution を更新できるようにします。

TaskExecution は、TaskExecution オブジェクトを保持するデータストアを参照する TaskRepository の実装で createTaskExecution メソッドを呼び出すことによって作成できます。

生成された TaskExecutionId を使用するようにタスクを構成するには、次のプロパティを追加します。

spring.cloud.task.executionid=yourtaskId

外部タスク ID

Spring Cloud Task を使用すると、各 TaskExecution の外部タスク ID を保存できます。生成された TaskExecutionId を使用するようにタスクを構成するには、次のプロパティを追加します。

spring.cloud.task.external-execution-id=<externalTaskId>

親タスク ID

Spring Cloud Task を使用すると、各 TaskExecution の親タスク ID を保存できます。この例としては、別のタスクを実行するタスクがあり、どのタスクが各子タスクを起動したかを記録したい場合があります。親 TaskExecutionId を設定するようにタスクを構成するには、子タスクに次のプロパティを追加します。

spring.cloud.task.parent-execution-id=<parentExecutionTaskId>

TaskConfigurer

TaskConfigurer は、Spring Cloud Task のコンポーネントの構成方法をカスタマイズできる戦略インターフェースです。デフォルトでは、論理デフォルトを提供する DefaultTaskConfigurer が提供されます。Map ベースのメモリ内コンポーネント (DataSource が提供されない場合に開発に役立ちます) および JDBC ベースのコンポーネント (DataSource が利用可能な場合に役立ちます)。

TaskConfigurer では、次の 3 つの主要コンポーネントを構成できます。

コンポーネント 説明 デフォルト (DefaultTaskConfigurer によって提供されました)

TaskRepository

使用する TaskRepository の実装。

SimpleTaskRepository

TaskExplorer

使用される TaskExplorer (タスクリポジトリへの読み取り専用アクセス用のコンポーネント) の実装。

SimpleTaskExplorer

PlatformTransactionManager

タスクの更新を実行するときに使用されるトランザクションマネージャー。

JdbcTransactionManager if a DataSource is used. ResourcelessTransactionManager if it is not.

You can customize any of the components described in the preceding table by creating a custom implementation of the TaskConfigurer interface. Typically, extending the DefaultTaskConfigurer (which is provided if a TaskConfigurer is not found) and overriding the required getter is sufficient. However, implementing your own from scratch may be required.

Users should not directly use getter methods from a TaskConfigurer directly unless they are using it to supply implementations to be exposed as Spring Beans.

Task Execution Listener

TaskExecutionListener lets you register listeners for specific events that occur during the task lifecycle. To do so, create a class that implements the TaskExecutionListener interface. The class that implements the TaskExecutionListener interface is notified of the following events:

  • onTaskStartup: Prior to storing the TaskExecution into the TaskRepository.

  • onTaskEnd: Prior to updating the TaskExecution entry in the TaskRepository and marking the final state of the task.

  • onTaskFailed: Prior to the onTaskEnd method being invoked when an unhandled exception is thrown by the task.

Spring Cloud Task also lets you add TaskExecution Listeners to methods within a bean by using the following method annotations:

  • @BeforeTask: Prior to the storing the TaskExecution into the TaskRepository

  • @AfterTask: タスクの最終状態をマークする TaskRepository 内の TaskExecution エントリを更新する前。

  • @FailedTask: 未処理の例外がタスクによってスローされたときに @AfterTask メソッドが呼び出される前。

次の例は、使用されている 3 つのアノテーションを示しています。

 public class MyBean {

	@BeforeTask
	public void methodA(TaskExecution taskExecution) {
	}

	@AfterTask
	public void methodB(TaskExecution taskExecution) {
	}

	@FailedTask
	public void methodC(TaskExecution taskExecution, Throwable throwable) {
	}
}
TaskLifecycleListener が存在する前に ApplicationListener を チェーン に挿入すると、予期しない影響が生じる可能性があります。

タスク実行リスナーによってスローされる例外

TaskExecutionListener イベントハンドラーによって例外がスローされた場合、そのイベントハンドラーのすべてのリスナー処理が停止します。例: 3 つの onTaskStartup リスナーが開始され、最初の onTaskStartup イベントハンドラーが例外をスローした場合、他の 2 つの onTaskStartup メソッドは呼び出されません。ただし、TaskExecutionListeners の他のイベントハンドラー (onTaskEnd および onTaskFailed) が呼び出されます。

TaskExecutionListener イベントハンドラーによって例外がスローされたときに返される終了コードは、ExitCodeEvent (Javadoc) によって報告された終了コードです。ExitCodeEvent が発行されない場合、スローされた例外が評価されて、型が ExitCodeGenerator であるかどうかが確認されます。存在する場合は、ExitCodeGenerator から終了コードを返します。それ以外の場合は、1 が返されます。

onTaskStartup メソッドで例外がスローされた場合、アプリケーションの終了コードは 1 になります。onTaskEnd または onTaskFailed メソッドで例外がスローされた場合、アプリケーションの終了コードは、上で列挙したルールを使用して確立されたコードになります。

onTaskStartuponTaskEnd、または onTaskFailed で例外がスローされた場合、ExitCodeExceptionMapper を使用してアプリケーションの終了コードをオーバーライドすることはできません。

終了メッセージ

TaskExecutionListener を使用すると、タスクの終了メッセージをプログラムで設定できます。これは、TaskExecution’sexitMessage を設定することによって行われ、その後 TaskExecutionListener に渡されます。次の例は、@AfterTaskExecutionListener のアノテーションが付けられたメソッドを示しています。

@AfterTask
public void afterMe(TaskExecution taskExecution) {
    taskExecution.setExitMessage("AFTER EXIT MESSAGE");
}

ExitMessage は、リスナーイベント (onTaskStartuponTaskFailedonTaskEnd) のいずれかで設定できます。3 つのリスナーの優先順位は次のとおりです。

  1. onTaskEnd

  2. onTaskFailed

  3. onTaskStartup

例: onTaskStartup および onTaskFailed リスナーに exitMessage を設定し、タスクが失敗せずに終了した場合、onTaskStartup からの exitMessage がリポジトリに保存されます。それ以外の場合、障害が発生すると、onTaskFailed から exitMessage が格納されます。また、onTaskEnd リスナーを使用して exitMessage を設定した場合、onTaskEnd の exitMessage が、onTaskStartup と onTaskFailed の両方からの終了メッセージよりも優先されます。

Spring Cloud Task インスタンスの制限

Spring Cloud Task を使用すると、指定されたタスク名のタスクを一度に 1 つだけ実行できるように設定できます。これを行うには、タスク名を確立し、タスク実行ごとに spring.cloud.task.single-instance-enabled=true を設定する必要があります。最初のタスクの実行中に、同じタスク名と spring.cloud.task.single-instance-enabled=true を持つタスクを実行しようとすると、タスクは失敗し、次のエラーメッセージが表示されます。Task with name "application" is already running.  spring.cloud.task.single-instance-enabled のデフォルト値は false です。次の例は、spring.cloud.task.single-instance-enabled を true に設定する方法を示しています。

spring.cloud.task.single-instance-enabled=true or false

この機能を使用するには、次の Spring Integration 依存関係をアプリケーションに追加する必要があります。

<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-core</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.integration</groupId>
    <artifactId>spring-integration-jdbc</artifactId>
</dependency>
この機能が有効になっており、別のタスクが同じタスク名で実行されているためにタスクが失敗した場合、アプリケーションの終了コードは 1 になります。

Spring AOT およびネイティブコンパイルの単一インスタンスの使用

ネイティブコンパイルされたアプリの作成時に Spring Cloud Task の単一インスタンス機能を使用するには、ビルド時に機能を有効にする必要があります。これを行うには、次のように process-aot 実行を追加し、JVM 引数として spring.cloud.task.single-step-instance-enabled=true を設定します。

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
        <execution>
            <id>process-aot</id>
            <goals>
                <goal>process-aot</goal>
            </goals>
            <configuration>
                <jvmArguments>
                    -Dspring.cloud.task.single-instance-enabled=true
                </jvmArguments>
            </configuration>
        </execution>
    </executions>
</plugin>

ApplicationRunner および CommandLineRunner の監視の有効化

ApplicationRunner または CommandLineRunner のタスク監視を有効にするには、spring.cloud.task.observation.enabled を true に設定します。

SimpleMeterRegistry を使用して観察を可能にするタスクアプリケーションの例は、ここにあります。

Spring Cloud Task 自動構成の無効化

Spring Cloud Task を実装用に自動構成すべきでない場合は、タスクの自動構成を無効にすることができます。これを行うには、次のアノテーションをタスクアプリケーションに追加します。

@EnableAutoConfiguration(exclude={SimpleTaskAutoConfiguration.class})

spring.cloud.task.autoconfiguration.enabled プロパティを false に設定して、タスクの自動構成を無効にすることもできます。

コンテキストを閉じる

アプリケーションがタスクの補完時に ApplicationContext を閉じる必要がある場合 (すべての *Runner#run メソッドが呼び出され、タスクリポジトリが更新されている場合)、プロパティ spring.cloud.task.closecontextEnabled を true に設定します。

コンテキストを閉じるもう 1 つのケースは、タスクの実行が完了してもアプリケーションが終了しない場合です。このような場合、スレッドが割り当てられているため、コンテキストは開いたままになります (たとえば、TaskExecutor を使用している場合)。このような場合は、タスクの起動時に spring.cloud.task.closecontextEnabled プロパティを true に設定します。これにより、タスクが完了するとアプリケーションのコンテキストが閉じられます。アプリケーションの終了が許可されます。

タスクメトリクスを有効にする

Spring Cloud Task は Micrometer と統合し、実行するタスクの監視を作成します。タスク監視の統合を有効にするには、spring-boot-starter-actuator、優先レジストリ実装 (メトリクスを公開する場合)、およびマイクロメータートレーシング (トレースデータを公開する場合) をタスクアプリケーションに追加する必要があります。Influx を使用してタスクの可観測性とメトリクスを有効にするための maven 依存関係セットの例は次のようになります。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-influx</artifactId>
    <scope>runtime</scope>
</dependency>

Spring タスクと Spring Cloud Task プロパティ

task という用語は業界で頻繁に使用される言葉です。このような例では、Spring Boot は spring.task を提供し、Spring Cloud Task は spring.cloud.task プロパティを提供します。このため、これら 2 つのプロパティグループが直接関連しているということで、過去に混乱が生じていました。ただし、これらは Spring エコシステムで提供される 2 つの異なる機能セットを表しています。

  • spring.task は、ThreadPoolTaskScheduler を構成するプロパティを指します。

  • spring.cloud.task は、Spring Cloud Task の機能を構成するプロパティを指します。