Spring の組み込みスケジューラは、Java でタイマータスクを実行する便利な方法を提供しますが、エンタープライズ環境では制限があります。Spring ジョブを SchedulerX と統合することで、モニタリング、高度なスケジューリング、高可用性などのエンタープライズ級の機能で強化できます。
前提条件
-
SchedulerX エージェントのバージョン 1.8.13 以降がインストールされていること。
-
Spring Boot アプリケーションが SchedulerX に接続されていること。詳細については、「SchedulerX への Spring Boot アプリケーションの接続」をご参照ください。
操作手順
手順 1:依存関係の追加
Spring Boot アプリケーションで、SchedulerX の依存関係を pom.xml ファイルに追加します。
schedulerx2.version には最新のエージェントバージョンを使用してください。詳細については、「エージェントリリースノート」をご参照ください。
<dependency>
<groupId>com.aliyun.schedulerx</groupId>
<artifactId>schedulerx2-spring-boot-starter</artifactId>
<version>${schedulerx2.version}</version>
<!-- Logback を使用する場合は、Log4j と Log4j2 を除外する必要があります。 -->
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
Spring ジョブを初めて使用する場合でも、既存のジョブがある場合でも、スケジューリングを有効にするためにメインクラスに @EnableScheduling アノテーションを保持する必要があります。
@SpringBootApplication
@EnableScheduling /** Spring のスケジュールジョブを有効にします。*/
public class SchedulerXWorkerApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerXWorkerApplication.class, args);
}
}
/** ネイティブの Spring スケジュールジョブクラスです。*/
@Service
public class SpringScheduledProcessor {
@Scheduled(cron = "0/2 * * * * ?")
public void hello() {
logger.info(DateUtil.now() + " hello world. start");
logger.info(DateUtil.now() + " hello world. end");
}
}
デフォルトでは、依存関係を追加した後、SchedulerX は既存の Spring ジョブを管理しません。ジョブは引き続き Spring コンテナーによってスケジュールされ、その実行に影響はありません。
手順 2:設定パラメーターの追加
SchedulerX が Spring ジョブを管理できるようにするには、次の設定を application.properties ファイルに追加します。
# 1. アプリケーションのアクセス設定
spring.schedulerx2.endpoint=${endpoint}
spring.schedulerx2.namespace=${namespace}
spring.schedulerx2.groupId=${groupId}
spring.schedulerx2.appKey=${appKey}
# 2. SchedulerX による Spring ジョブの管理を有効化
spring.schedulerx2.task.scheduling.scheduler=schedulerx
# 3. (任意) 既存の Spring ジョブの自動同期を有効化
#spring.schedulerx2.task.scheduling.sync=true
#spring.schedulerx2.regionId=ジョブ同期用のリージョン ID を指定します。
#spring.schedulerx2.aliyunAccessKey=XXXXXXXXX
#spring.schedulerx2.aliyunSecretKey=XXXXXXXXX
パラメーターの説明:
-
アプリケーションのアクセス設定:SchedulerX コンソールにログインします。左側のナビゲーションペインで Application Management をクリックします。対象のアプリケーションを見つけ、Actions 列の [Access Configuration] をクリックして認証情報を取得します。初めて接続する場合は、アプリケーション グループを作成する必要があります。
-
自動同期設定:既存の Spring ジョブが多数ある場合は、自動同期を有効にすることで、手順 3 で説明されているようなタスクの手動作成を回避できます。リージョン ID のリストについては、「エンドポイント」をご参照ください。
クラスター環境でネイティブの Spring ジョブを実行するルールとの一貫性を保つため、SchedulerX プラットフォームに自動同期されたジョブは、デフォルトでブロードキャスト実行モードを使用します。これは、クラスター内の各マシンがスケジュールされた時間にジョブを実行することを意味します。ビジネス要件でクラスター内の 1 台のマシンのみがジョブを実行する必要がある場合は、コンソールでジョブの実行モードをスタンドアロン実行に編集できます。パラメーターの詳細については、手順 3 をご参照ください。
手順 3 (任意):タスクの手動作成
手順 2 で自動同期を有効にした場合は、この手順をスキップできます。
-
SchedulerX コンソールにログインします。
-
左側のナビゲーションペインで、[task management] をクリックします。
-
[task management] ページで Create Task をクリックします。タスクタイプとして [SpringSchedule] を選択し、クラス名とメソッド名を設定します。
パラメーター
説明
[Name]
タスクを識別するための一意の名前。
[Description]
タスクの検索と管理に役立つ任意の説明。
[Application ID]
タスクが属するアプリケーション グループ。ドロップダウンリストからオプションを選択します。
[Job Type]
タスクのプロセッサータイプ。有効な値: Java、Shell、Python、Go、HTTP、Node.js、[SpringSchedule]、XXL-JOB、DataWorks。Shell、Python、または Go を選択した場合、スクリプトエディターが表示されます。
このチュートリアルでは、[SpringSchedule] を選択します。
Spring Schedule の設定
タスクの完全修飾クラス名とメソッド名。
[Execution Mode]
複数のインスタンスでタスクをどのように実行するかを指定します。次のモードがサポートされています:
-
スタンドアロン実行:ランダムに選択された 1 つのインスタンスでタスクを実行します。
-
ブロードキャスト実行:すべてのインスタンスで同時にタスクを実行します。
説明詳細設定は、選択された実行モードによって変わります。
[Priority]
同じアプリケーション内の複数のタスクが同じインスタンスで実行可能な状態になった場合、優先度の高いタスクが先に実行されます。SchedulerX は、プリエンプティブな優先度付きキューを使用して、異なるインスタンス間でも高優先度のタスクが確実に先に実行されるようにします。詳細については、「優先度付きキューによるアプリケーションレベルのスロットリング」をご参照ください。
[Job Parameters]
実行時にジョブコンテキストから取得できるカスタム文字列。
-
-
スケジュールを設定します。
説明コンソールで設定したスケジュールは、コード内の
@Scheduledアノテーションで指定されたスケジュールを上書きします。ただし、コード内のアノテーションは保持する必要があります。次の表では、時間ベースのパラメーターについて説明します。
パラメーター
説明
[Time Type]
-
none:タスクはスケジュールされず、通常はワークフローによってトリガーされます。
-
cron:タスクは Cron 式を使用してスケジュールされます。
-
api:タスクは API 呼び出しによってトリガーされます。
-
fixed_rate:タスクは固定頻度でトリガーされます。
-
second_delay:タスクは秒単位の固定遅延の後にトリガーされます。
-
one_time:タスクは 1 回だけ実行されます。
[Cron Expression] (cron 時間タイプのみ)
標準の Cron 式を入力します。組み込みツールを使用して式を生成し、検証することもできます。
固定頻度 (fixed_rate 時間タイプのみ)
間隔を秒単位で入力します。値は 60 以上である必要があります。たとえば、値 200 は、タスクが 200 秒ごとに実行されることを意味します。
固定遅延 (second_delay 時間タイプのみ)
遅延を秒単位で入力します。値は 1 から 60 の範囲である必要があります。たとえば、値 5 は、タスクがスケジュールされた時刻の 5 秒後にトリガーされることを意味します。
次の表では、詳細設定パラメーターについて説明します。
パラメーター
説明
[Data Timestamp Offset]
データタイムスタンプとスケジュール時刻のオフセット。この値は実行時にジョブコンテキストから取得できます。
[Time Zone]
ビジネス要件に基づいてタイムゾーンを選択します。リージョンタイムゾーンと標準 GMT タイムゾーンの両方がサポートされています。
[Calendar]
営業日カレンダーや金融日カレンダーなどのカレンダーを選択して、タスクの実行を特定の日に制限できます。
-
-
アラートルールと通知チャネルを設定します。詳細については、「通知先の管理」をご参照ください。
これらの手順を完了すると、SchedulerX が Spring ジョブを管理し、ビジュアルモニタリング、ログクエリ、実行トレース、アラートなどのエンタープライズ級の機能を提供します。
手順 4:統合の検証
-
Spring アプリケーションを起動します。起動後、SchedulerX コンソールにログインし、左側のナビゲーションペインで Application Management をクリックします。アプリケーションのインスタンスがリストに表示されていることを確認します。
[Instances] 列で、数値が 0 より大きいことを確認します。[View Instances] をクリックして、接続されているインスタンスの詳細を確認することもできます。
-
左側のナビゲーションペインで [task management] をクリックします。アプリケーションのタスクを見つけ、Actions 列の Run Once をクリックします。実行が成功すれば、統合が確認されます。
よくある質問
SchedulerX がスケジュールされた Spring ジョブを引き継いだ後、元の Spring タイマーが引き続き実行されるのはなぜですか?
アプリケーションでカスタムスケジューラが指定されている場合、SchedulerX はカスタムスケジューラを上書きします。org.springframework.scheduling.annotation.SchedulingConfigurer インターフェースを実装するクラスがアプリケーションプロジェクトに存在するかどうか、および ScheduledTaskRegistrar の setScheduler メソッドがデフォルトのスケジューラを上書きするために呼び出されているかどうかを確認します。クラスが存在する場合、またはデフォルトのスケジューラが上書きされている場合は、関連するコードをコメントアウトします。
Spring ジョブのコンテキストを取得するにはどうすればよいですか?
コンテキストを取得するには、次のコードをアプリケーションプロジェクトコードに追加します。
JobContext jobContext = ContainerFactory.getContainerPool().getContext();Spring ジョブは処理結果を返しますか?
エージェントのバージョンが 1.10.11 以降の場合、Spring ジョブは処理結果を返すことができます。処理結果は、指定されたスケジューリング方法に基づいて返されます。
@Scheduled(cron = "0/5 * * * * ?")
public ProcessResult helloStandalone1() {
try {
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. start"); // 処理開始のログ出力
TimeUnit.SECONDS.sleep(2L); // 2秒待機
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. end"); // 処理終了のログ出力
} catch (Exception e) {
e.printStackTrace();
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. exception end.."); // 例外発生時のログ出力
}
return new ProcessResult(true, "Processing result"); // 処理結果を返す
}
@Scheduled(cron = "0/5 * * * * ?")
public String helloStandalone2() {
try {
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. start"); // 処理開始のログ出力
TimeUnit.SECONDS.sleep(2L); // 2秒待機
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. end"); // 処理終了のログ出力
} catch (Exception e) {
e.printStackTrace();
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. exception end.."); // 例外発生時のログ出力
}
return "Processing result"; // 処理結果を返す
}