このドキュメントでは、SchedulerX における一般的なジョブ管理の問題をトラブルシューティングする方法について説明します。
Spring Bean が見つからない問題のトラブルシューティング
アプリケーション管理でワーカーに接続し、起動モードが Spring または Spring Boot であることを確認します。
JobProcessorをbeanとして注入します。たとえば、@Componentアノテーションを追加します。pom の依存関係を確認します。
spring-boot-devtoolsに依存している場合は、必ず除外してください。JobProcessor または process メソッドが AOP アノテーションを使用している場合、SchedulerX エージェントを最新バージョンにスペックアップしてください。旧バージョンでは AOP がサポートされていません。
プロキシレイヤーが追加されることで Bean タイプの不一致が発生することがあります。これを診断するには、
DefaultListableBeanFactoryクラスにブレークポイントを設定します。beanDefinitionNamesメンバー変数には Spring に登録されたすべての Bean のリストが含まれます。このリストを確認して、Bean がアスペクトによってプロキシされているかどうかを調べてください。これは、誤ったサードパーティ製ライブラリが間接的にインポートされている場合に発生することがあります。その場合は、該当のライブラリを除外してください。
上記の解決策でも問題が解消しない場合は、ThreadContainer.start メソッドをデバッグしてください。存在すると分かっているクラスに対して class.forName エラーが発生する場合は、アプリケーションがクラスローダーの不整合を引き起こすフレームワークを使用している可能性があります。SchedulerxWorker.setClassLoader を設定することで、この問題を解決できます。
「Unable to make field private」エラーによるジョブ失敗
MapReduce はシリアル化および逆シリアル化のフレームワークを使用します。Java 9 以降では、プライベート変数へのリフレクティブアクセスを手動で有効にする必要があります。JVM 引数に次のパラメーターを追加してください。
--add-opens java.base/java.lang=ALL-UNNAMED「submit jobInstanceId to worker timeout」エラーによるジョブ失敗
このエラーは、アプリケーションリリース時のみ発生する場合や、まれにしか発生しない場合は無視しても問題ありません。
同じ workerAddr でエラーが継続する場合は、サーバーとエージェント間の持続的接続が切断されていることを示しています。ワーカーノードを再起動するか、SchedulerX エージェントをアップグレードしてください。アップグレード後、エージェントは自動的に切断された接続を復元できます。
「used space beyond 90.0% !」エラーによるジョブ失敗
ディスク領域が不足しています。ECS インスタンスまたはコンテナのディスク領域を解放する必要があります。
「ClassNotFoundException」エラーによるジョブ失敗
このエラーは、ジョブを実行しているワーカー上でクラスが見つからなかったことを示しています。Java ジョブ用に設定された Class full path が、省略形ではなく完全修飾名であることを確認してください。
たとえば、正しい完全修飾パスは com.aliyun.schedulerx.example.processor.DtsSimpleJob です。
設定された Class full path が正しいにもかかわらずエラーが発生する場合は、ワーカー上にクラスが存在しません。これは通常、誤ったパッケージをデプロイしているか、アプリケーションが他のユーザーのワーカーに接続していることが原因です。ワーカーにログインして、デコンパイラを使用して調査できます。
「jobInstance = xxx don't update progress more than 60s」エラーによるジョブ失敗
サーバーは、ジョブを実行中のワーカーが停止またはリリース中であり、かつ 60 秒以上進捗を報告しない場合、ジョブを強制終了します。ワーカーの問題が原因であるか、ワーカーがすでに存在しないことを確認できた場合は、特に操作を行う必要はありません。
エラーメッセージなしでジョブが失敗
症状:
ジョブが失敗しましたが、エラーメッセージが表示されません。
考えられる原因:
ワーカーの障害またはビジネスロジックの障害です。
解決策:
インスタンスページ で、Task instance List タブに移動します。対象のジョブインスタンスを見つけ、詳細 列の Actions をクリックして、Task instance details パネルを開き、ジョブが失敗したワーカーを特定します。
これがジョブを実行しているワーカーのアドレスです。
ワーカーにログインし、~/logs/schedulerx/worker.log ログファイルを開きます。
grep <Instance ID> worker.logを実行して、インスタンスに関連するログを表示します。ERROR レベルの例外が存在する場合は、スタックトレースを確認して具体的な原因を特定してください。エラーの説明が空の場合、問題はビジネスロジック内にあり、失敗メッセージが返されていない可能性があります。ビジネスコードを調査して原因を特定してください。
エラーの説明にフレームワークの例外が含まれている場合は、DingTalk グループ (ID: 23103656) に参加して SchedulerX テクニカルサポートにお問い合わせください。
ジョブ失敗のトラブルシューティング
例外をスローするスタンドアロンジョブの場合は、インスタンスページ で Task instance List タブをクリックし、対象のジョブインスタンスを見つけ、詳細 列の Actions をクリックしてエラーメッセージを表示します。
ジョブが例外をスローしない場合、または分散ジョブの場合は、Professional Edition アプリケーションで Log Service を使用して問題をトラブルシューティングできます。
Basic Edition アプリケーションの場合は、ワーカーノードにログインして SchedulerX ログおよびビジネスログを確認してください。
ジョブがハングする
症状:
スケジュールされたジョブが実行中の状態で停止し、完了しません。
考えられる原因:
ビジネスロジックの問題です。
SchedulerX の問題です。
解決策: ビジネスロジックの問題は以下の手順でトラブルシューティングできます。その他の問題については、DingTalk グループ (ID: 23103656) に参加して SchedulerX テクニカルサポートにお問い合わせください。
Professional Edition アプリケーションの場合: コンソールの ThreadDump を使用して、ジョブの例外スタックトレースを取得します。この機能は、エージェントバージョン 1.4.2 以降で利用可能です。
Basic Edition アプリケーションの場合: ハングしているワーカーノードにログインし、
jstackコマンドを使用してスタックトレースを表示します。次のコマンドを実行します。jstack <pid> | grep <job instance ID> -A 20$jstack 29191 |grep 58903617 -A 200 "Schedulerx-Container-Thread-58903617-0" #4093 prio=5 os_prio=0 tid=xxx nid=xxx waiting on condition [0x00002ad443101000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x000000072b837ae0> (a java.util.concurrent.CountDownLatch$Sync) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836) at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304) at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231) at com.aliyun.ticket.importworker.WOImportJob.startImport(WOImportJob.java:353) at com.aliyun.ticket.importworker.WOImportJob.doImportForAll(WOImportJob.java:242) at com.aliyun.ticket.importworker.WOImportJob.process(WOImportJob.java:163) at com.alibaba.schedulerx.worker.container.ThreadContainer.start(ThreadContainer.java:90) at com.alibaba.schedulerx.worker.container.ThreadContainer.run(ThreadContainer.java:60) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:756) "Container-Batch-Statues-Retrieve-Thread-58903617" #4092 prio=5 os_prio=0 tid=xxx nid=xxx waiting on condition [0x00002ad44fe0e000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at com.alibaba.schedulerx.worker.batch.BaseReqHandler$2.run(BaseReqHandler.java:74) at java.lang.Thread.run(Thread.java:756) "TDDL-Druid-ConnectionPool-DestroyScheduler--2-thread-237" #4052 daemon prio=5 os_prio=0 tid=xxx nid=xxx waiting on condition [0x00002ad462e00] java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000007436c7190> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078) at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:1129) at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:809) at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1066) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
ジョブの実行が遅い場合のトラブルシューティング
Professional Edition でトレーシング分析を有効にしてください。詳細については、「トレーシング分析の統合」をご参照ください。
ジョブインスタンスの上限に達した
症状:
ジョブ管理ページで、Run once をクリックすると、次のプロンプトが表示されます:
実行中のジョブインスタンス数が上限に達しました。しばらくしてから再度お試しください。考えられる原因:
このジョブのインスタンスがすでに実行中です。
実行中のジョブインスタンス数が、ジョブに設定された最大同時実行数に達しています。
解決策:
同時実行数の設定が適切な場合は、特に操作を行う必要はありません。ジョブ管理 ページで、 をクリックして、実行中のジョブインスタンスを確認できます。
この同時実行数の制限が厳しすぎる場合は、ジョブの Edit 列の Actions をクリックし、詳細設定で Instance concurrency を増やしてください。
未完了のジョブ:キュー待ちかスキップか?
デフォルトでは、インスタンスの同時実行数は 1 に設定されており、ジョブは直列で実行されます。長時間実行されるジョブが次のスケジュール時刻までに完了していない場合、新しい実行はキューに入れられず、破棄されます。
インスタンスの同時実行数が 2 に設定されている場合、前の実行が完了していなくても、次のスケジュール時刻に別のインスタンスを開始できます。最大で 2 つのジョブインスタンスを同時に実行できます。
一回限りのジョブを作成する
一回限りのジョブを作成するには、時間タイプとして one_time を選択します。SchedulerX 2.0 はこの機能をサポートしていますが、これらのジョブは実行レコードを保持しません。
一回限りのジョブの履歴を表示する
one_time ジョブはデータの蓄積を防ぐために実行後に自動的に削除され、履歴は保持されません。実行レコードを保存する必要がある場合は、Log Service を有効にしてください。これにより、すべてのジョブの実行ログが過去 2 週間分保持され、トラブルシューティングに役立ちます。Log Service の有効化方法の詳細については、「アプリケーション管理」をご参照ください。
第2レベルスケジューリングの設定
SchedulerX は秒単位のスケジューリングをサポートしています。cron および fix_rate の時間タイプは秒単位のスケジューリングをサポートしていません。second_delay の時間タイプを選択すると、前回の実行が完了してから指定された秒数後にジョブを実行できます。
ジョブがスケジュールされない
スタンドアロンジョブが特定の時刻にスケジュールされない場合は、ワーカーリストにワーカーが存在するか、およびすべてのワーカーがビジー状態でないかを確認してください。利用可能なワーカーがない場合は、「ワーカーが利用できない」または「すべてのワーカーがビジー状態」の状態に基づいてトラブルシューティングを行ってください。詳細については、「ワーカーが利用できない場合はどうすればよいですか?」および「すべてのワーカーがビジー状態の場合はどうすればよいですか?」をご参照ください。
ジョブに対してワーカーが利用できない場合のアラームを設定することを推奨します。詳細については、「ジョブ管理」をご参照ください。
SchedulerX でタイムアウトを設定する
SchedulerX はジョブ全体のタイムアウトをサポートしていますが、個々のタスクのタイムアウトはサポートしていません。コンソールでタイムアウトを動的に変更できます。詳細については、「ジョブ管理」をご参照ください。
インスタンスを停止した後も実行が継続する
症状: インスタンスを停止した後も実行が継続します。
考えられる原因: ジョブインスタンスを停止すると、SchedulerX はエージェントに kill メッセージを送信します。その後、エージェントは新しいタスクのディスパッチを停止し、インスタンスコンテキストおよびそのスレッドプールを破棄します。ただし、すでに進行中のタスクは強制終了されません。これらのスレッドは中断されるだけであり、完了まで実行を続けます。
解決策:
ほとんどの場合、特に操作を行う必要はありません。タスクが完了するまでお待ちください。
インスタンスを停止した際に実行中のすべてのタスクを即座に終了させる必要がある場合は、タスク処理ロジックを変更して、現在のスレッドの中断状態を処理できるようにする必要があります。
高度なジョブ設定を構成する
詳細については、「ジョブ管理の高度なパラメーター」をご参照ください。
すべてのワーカーがビジー状態
アプリケーション管理ページでインスタンスを表示し、ビジーワーカーを特定します。次に、Busy をクリックして、どのメトリックがしきい値を超えているかを確認します。
ビジーしきい値は、Application Management ページで アプリケーショングループの編集 をクリックして設定します。
基本設定 ステップの インスタンスのビジー設定 セクションで、load5(デフォルト:0)、メモリ使用量(デフォルト:90 %)、ディスク使用量(デフォルト:95 %)のしきい値を設定できます。また、ビジーワーカーチェックを有効化 スイッチを使用して、ビジーチェックを有効にするかどうかを制御できます。
ワーカーが高負荷によりビジー状態になっている場合は、アプリケーションがコンテナ(Kubernetes)にデプロイされているかを確認してください。その場合は、次の 2 つのパラメーターを設定する必要があります。設定しないと、収集された CPU 使用量が正確でない可能性があります。詳細については、「Spring Boot アプリケーションを SchedulerX に接続する」をご参照ください。
パラメーター | 説明 | 値 | 初期バージョン |
spring.schedulerx2.enableCgroupMetrics | エージェントインスタンスのメトリック収集に cgroup を使用するかどうかを指定します。コンテナ(Kubernetes)環境では、手動で有効にする必要があります。 | true/false。デフォルト:false。 | 1.2.2.2 |
spring.schedulerx2.cgroupPathPrefix | コンテナ内の cgroup パス。 | デフォルト:/sys/fs/cgroup/cpu/。このパスが存在する場合は、このパラメーターを設定する必要はありません。 | 1.2.2.2 |
トレーシング分析の統合
ジョブスケジューリングはエンドツーエンドのトレーシング分析をサポートしています。詳細については、「トレーシング分析の統合」をご参照ください。
アプリケーションリリース中にジョブがハングまたは遅延する
症状: アプリケーションリリース中にジョブの実行がハングまたは遅延します。
考えられる原因: 分散ジョブの場合、タスクを処理中のワーカーがオフラインになると、そのタスクは再分配され、システムはワーカーがオンラインかどうかをポーリングします。このプロセスにより、全体的な実行が遅くなる可能性があります。
解決策: エージェントを最新バージョンにスペックアップしてください。バージョン 1.7.9 以降には、この問題に対する最適化が含まれています。
一回限りの実行時のインスタンスパラメーター
ジョブ管理 ページで、Run once 列の Actions をクリックして、スケジュールされたジョブを一度だけ実行します。表示されるダイアログボックスで、ワーカーを指定し、Instance Parameters を設定できます。これはテスト用途を中心に使用されるオプションパラメーターです。
インスタンスパラメーターとジョブパラメーターの違い
インスタンスパラメーターとジョブパラメーターは異なる概念です。コードで取得するパラメーターは、ビジネスロジックによって決まります。
ジョブパラメーターまたはインスタンスパラメーターの取得
次のコードは、パラメーターを取得する方法を示しています。
@Component
public class JavaDemoProcessor extends JavaProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger("schedulerxLog");
@Override
public ProcessResult process(JobContext jobContext) throws InterruptedException {
LOGGER.info(JSON.toJSONString(jobContext));
// ジョブパラメーターを取得
String jobParameters = jobContext.getJobParameters();
// インスタンスパラメーターを取得
String instanceParameters = jobContext.getInstanceParameters();
LOGGER.info("Job parameters: " + jobParameters);
LOGGER.info("Instance parameters: " + instanceParameters);
return new ProcessResult(InstanceStatus.SUCCESS);
}
}インスタンスパラメーターを優先し、ジョブパラメーターをフォールバックとして取得する
次のコードは、その詳細を示しています。
@Component
public class JavaDemoProcessor extends JavaProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger("schedulerxLog");
@Override
public ProcessResult process(JobContext jobContext) throws InterruptedException {
String params = null;
if (StringUtils.isNotBlank(jobContext.getInstanceParameters())) {
params = jobContext.getInstanceParameters();
} else {
params = jobContext.getJobParameters();
}
LOGGER.info("JavaDemoProcessor params:{}", params);
return new ProcessResult(InstanceStatus.SUCCESS);
}
}