SchedulerX は、コードの変更を最小限に抑えながら、既存の Spring @Scheduled ジョブを引き継ぎ、集中管理、モニタリング、アラート機能、分散スケジューリングを追加します。ジョブのロジックやアノテーションを変更する必要はありません。
仕組み
SchedulerX は、デフォルトの Spring タスクスケジューラを独自のスケジューリングエンジンで置き換えます。
プロジェクトに SchedulerX Spring Boot Starter の依存関係を追加します。
アプリケーションのプロパティファイルに
spring.schedulerx2.task.scheduling.scheduler=schedulerxを設定します。SchedulerX がすべての
@Scheduledメソッドの実行をコンソール経由で制御します。
ジョブの引き継ぎ後、スケジュール頻度は SchedulerX コンソールで制御されます。@Scheduled アノテーション内の cron 式はコード内に残りますが、ジョブの実行タイミングを決定しなくなります。
実行モード:
| モード | 動作 | 利用シーン |
|---|---|---|
| ブロードキャスト実行 | すべてのワーカーノードでジョブを同時に実行します。 | キャッシュのリフレッシュ、ログのクリーンアップ、構成の再読み込みなど、各ノードで必ず実行する必要があるタスクです。ネイティブな Spring @Scheduled の動作と一致します。 |
| スタンドアローン実行 | クラスター内でランダムに選択された 1 つのワーカーがジョブを実行します。 | データ集約、レポート生成、メール配信など、クラスター全体で厳密に 1 回だけ実行する必要があるタスクです。 |
自動同期されたジョブは、ネイティブな Spring 動作を維持するため、デフォルトで ブロードキャスト実行 モードになります。ジョブを単一ノードでのみ実行したい場合は、コンソールで 実行モード を スタンドアローン実行 に変更してください。
前提条件
SchedulerX エージェントのバージョンが 1.8.13 以降
SchedulerX に接続済みの Spring Boot アプリケーション。設定手順については、「Spring Boot アプリケーションを SchedulerX に接続する」をご参照ください。
Maven 依存関係の追加
schedulerx2-spring-boot-starter の依存関係を pom.xml に追加します。schedulerx2.version は、エージェントのリリースノート から最新バージョンに置き換えてください。
<dependency>
<groupId>com.aliyun.schedulerx</groupId>
<artifactId>schedulerx2-spring-boot-starter</artifactId>
<version>${schedulerx2.version}</version>
<!-- アプリケーションで Logback を使用している場合、Log4j を除外 -->
<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>SchedulerX がスケジューリングを処理するかどうかに関わらず、メインクラスには @EnableScheduling を保持してください。
@SpringBootApplication
@EnableScheduling // 必須:削除しないでください
public class SchedulerXWorkerApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerXWorkerApplication.class, args);
}
}既存の @Scheduled ジョブクラスは、変更の必要はありません。
@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 コンテナ内で引き続き実行されます。
SchedulerX による引き継ぎの構成
application.properties ファイルに以下のプロパティを追加します。
# SchedulerX への接続
spring.schedulerx2.endpoint=${endpoint}
spring.schedulerx2.namespace=${namespace}
spring.schedulerx2.groupId=${groupId}
spring.schedulerx2.appKey=${appKey}
# Spring スケジュールジョブの SchedulerX による引き継ぎを有効化
spring.schedulerx2.task.scheduling.scheduler=schedulerx接続パラメーター(endpoint、namespace、groupId、appKey)を取得するには、以下の手順を実行します。
SchedulerX コンソール にログインします。
左側のナビゲーションウィンドウで、アプリケーション管理 をクリックします。
対象のアプリケーションを見つけ、アクセス構成 を 操作 列からクリックします。
まだ SchedulerX にアプリケーションを作成していない場合は、まずアプリケーションを作成してください。
ジョブ登録方法の選択
引き継ぎを有効化した後、Spring ジョブを SchedulerX に登録するには、以下のいずれかの方法を選択します。
| オプション | 推奨される利用シーン | 方法 |
|---|---|---|
| 自動同期(推奨) | 多数の既存 @Scheduled ジョブがある場合 | 構成プロパティを追加(以下参照) |
| 手動登録 | 個々のジョブの選択的なコントロール | SchedulerX コンソールでジョブを 1 つずつ作成 |
オプション A:既存ジョブの自動同期(推奨)
すべての @Scheduled ジョブを SchedulerX に自動同期するには、以下のプロパティを追加します。
# 自動ジョブ同期を有効化
spring.schedulerx2.task.scheduling.sync=true
spring.schedulerx2.regionId=<region-id>
spring.schedulerx2.aliyunAccessKey=<your-access-key>
spring.schedulerx2.aliyunSecretKey=<your-secret-key>プレースホルダーを実際の値に置き換えてください。
| プレースホルダー | 説明 | 例 |
|---|---|---|
<region-id> | SchedulerX インスタンスが実行されているリージョンです。「エンドポイント」をご参照ください。 | cn-hangzhou |
<your-access-key> | Alibaba Cloud の AccessKey ID | LTAI5tXxx |
<your-secret-key> | Alibaba Cloud の AccessKey シークレット | xXxXxXx |
自動同期されたジョブは、ネイティブな Spring 動作と一致させるため、デフォルトで ブロードキャスト実行 モードになります。ジョブを単一ノードでのみ実行したい場合は、コンソールでその 実行モード を スタンドアローン実行 に変更してください。
オプション B:ジョブの手動登録
ジョブを個別に登録するには、コンソールでジョブを 1 つずつ作成します。
SchedulerX コンソール にログインします。
左側のナビゲーションウィンドウで、タスク管理 をクリックします。
タスク管理 ページで、タスクの作成 をクリックします。
タスクタイプ を SpringSchedule に設定し、残りのパラメーターを構成します。
ジョブパラメーター
| パラメーター | 説明 |
|---|---|
| タスク名 | ジョブの名前です。 |
| 説明 | 検索および管理用の簡潔な説明です。 |
| アプリケーション ID | ジョブが属するアプリケーショングループです。ドロップダウンリストから選択します。 |
| タスクタイプ | ジョブのタイプです。Spring ジョブの場合は SpringSchedule を指定します。その他の有効な値:Java、Shell、Python、Golang、Http、Node.js、XXL-JOB、DataWorks。 |
| spring scheduleConfiguration | ジョブの完全修飾クラス名とメソッド名です。 |
| 実行モード | クラスター全体でのジョブの実行方法です。スタンドアローン実行:ランダムに選択された 1 つのワーカーがジョブを実行します。ブロードキャスト実行:すべてのワーカーがジョブを同時に実行します。 |
| 優先度 | 同一アプリケーション内で複数のジョブが同時にトリガーされた場合の実行順序です。優先度が高いジョブが先に実行されます。ワーカー間での優先度保証については、「プリエンプティブルキュー」をご参照ください。 |
| タスクパラメーター | 実行コンテキストを介してジョブに渡す任意の文字列です。 |
トリガーフレキエンシー
SchedulerX コンソールで設定したスケジュールが、コード内の @Scheduled アノテーションよりも優先されます。アノテーションはソースコード内に残りますが、実行タイミングの制御には使用されません。| パラメーター | 説明 |
|---|---|
| 時間タイプ | none:ワークフローによってトリガーされます。cron:cron 式でスケジュールされます。api:API 呼び出しによってトリガーされます。fixed_rate:固定間隔(60 秒超)でトリガーされます。second_delay:1~60 秒の遅延でトリガーされます。one_time:特定の時刻に 1 回だけトリガーされます。 |
| cron 式 | スケジューリング用の cron 式です。手動入力または組み込みジェネレーターを使用できます。 |
| 固定頻度 | 時間タイプ が fixed_rate の場合にのみ利用可能です。秒単位の間隔を指定します。値は 60 より大きくなければなりません。 |
| 固定遅延 | 秒単位の遅延(1~60)。時間タイプ が second_delay の場合にのみ利用可能です。 |
高度なタイミングパラメーター
| パラメーター | 説明 |
|---|---|
| タイムオフセット | データタイムスタンプとジョブのトリガー時刻との間のオフセットです。ランタイム時に実行コンテキストから取得されます。 |
| タイムゾーン | スケジューリングに使用するタイムゾーンです。国/地域または GMT オフセットから選択します。 |
| カレンダー | ビジネスカレンダーのタイプ:営業日 または 金融日。 |
アラート条件および通知方法を構成します。詳細については、「通知連絡先および通知連絡先グループ」をご参照ください。
接続の確認
Spring Boot アプリケーションを起動します。
SchedulerX コンソール にログインします。
左側のナビゲーションウィンドウで、アプリケーション管理 をクリックします。
アプリケーションの インスタンス総数 列を確認します。0 より大きい値が表示されれば、接続が成功しています。

左側のナビゲーションウィンドウで、タスク管理 をクリックします。
対象のジョブを見つけ、1 回実行 を 操作 列からクリックします。
ジョブが正常に実行されることを確認します。
確認後、SchedulerX により、Spring ジョブに対して視覚化された管理・制御、ログ照会、実行チェーンのトレーシング、アラート機能といった企業向け機能が提供されます。
よくある質問
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);
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);
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";
}引き継ぎ後も元の Spring スケジューラが実行され続けます
これは、アプリケーションでカスタムスケジューラが定義されている場合に発生します。org.springframework.scheduling.annotation.SchedulingConfigurer インターフェイスを実装するクラスがアプリケーションに存在し、ScheduledTaskRegistrar の setScheduler メソッドが呼び出されているかどうかを確認してください。該当する場合、そのコードをコメントアウトしてください。SchedulerX はカスタムスケジューラを上書きできません。
実行コンテキストの取得
JobContext を ContainerFactory 経由で取得します。
JobContext jobContext = ContainerFactory.getContainerPool().getContext();処理結果の返却
エージェントのバージョンが 1.10.11 より新しいこと が必要です。以下の 2 種類の戻り値がサポートされています。
ステータスフラグとメッセージを含む ProcessResult を返す場合:
@Scheduled(cron = "0/5 * * * * ?")
public ProcessResult helloStandalone1() {
try {
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. start");
TimeUnit.SECONDS.sleep(2L);
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");
}単純な String を返す場合:
@Scheduled(cron = "0/5 * * * * ?")
public String helloStandalone2() {
try {
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. start");
TimeUnit.SECONDS.sleep(2L);
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";
}