Javaで外部APIを毎分ポーリングする処理は、一見すると「1分ごとにHTTP通信するだけ」に見えますが、実際に運用へ乗せると失敗時の再試行、タイムアウト、重複実行、防止、取得データの整合性、API側への負荷制御まで考える必要があります。私自身も定期実行バッチや外部連携の仕組みを扱う中で、最初は単純なスケジュール実行で十分だと思っていたものの、しばらく運用すると
「前回処理が終わる前に次回が始まる」
「一時的な通信断で異常終了する」
「同じデータを二重処理する」
といった問題が出やすいと感じました。
Javaで毎分ポーリングを安定運用するには、単純な定期実行だけでなく、タイムアウト設定、排他制御、再試行方針、取得済みデータの管理、ログ設計の5点を先に固めておくことが重要です。特に本番環境では、APIが正常に見えてもネットワークや相手側制限で失敗することがあるため、「失敗しない実装」ではなく「失敗しても壊れにくい実装」を目指した方が安全です。
Javaで外部APIを毎分ポーリングするとは
外部APIのポーリングとは、一定間隔でAPIへアクセスし、新しいデータや状態変更がないかを確認する処理です。今回のような毎分ポーリングでは、60秒ごとにAPIを呼び出して、レスポンスに含まれる情報を取り込みます。
よくある利用例は次の通りです。
| 利用シーン | 内容 |
|---|---|
| 注文情報の取得 | 外部サービス側で発生した新規注文を1分ごとに確認する |
| ステータス監視 | 決済結果や処理状況を定期的に取得する |
| 在庫・価格連携 | 外部システムのデータ更新を定期反映する |
| 通知連携 | 新着データを取得して自社側で通知処理を行う |
毎分ポーリングはリアルタイム性と実装のしやすさのバランスが取りやすい反面、回数が多いため、API側に無駄な負荷をかけない作りが必要です。
毎分ポーリング実装で先に押さえるべきポイント
最初に、設計時点で確認しておきたい重要ポイントを表にまとめます。
| 項目 | 確認内容 | 理由 |
|---|---|---|
| 実行間隔 | 本当に毎分が必要か | 不要に短い間隔はAPI負荷と障害率を上げるため |
| タイムアウト | 接続タイムアウト、読み取りタイムアウトを設定する | 通信待ちで処理が詰まるのを防ぐため |
| 排他制御 | 前回処理が終わる前に次回が起動しないようにする | 二重実行や重複登録を防ぐため |
| 再試行 | 一時障害時のリトライ回数と間隔を決める | 短時間の失敗で止まらないようにするため |
| 重複防止 | 最終取得時刻や最新IDを保持する | 同じデータの再処理を防ぐため |
| ログ | 成功・失敗・取得件数・処理時間を記録する | 障害調査と運用監視のため |
このあたりを曖昧にしたまま作ると、実装直後は動いても、運用が始まってから手戻りしやすくなります。
スケジューリングには何を使うべきか
Javaで毎分実行する方法はいくつかありますが、業務システムではSpring Bootの @Scheduled や ScheduledExecutorService を使うことが多いです。
使い分けの目安は次の通りです。
| 方法 | 向いているケース | 特徴 |
|---|---|---|
| @Scheduled | Spring Bootアプリで定期実行したい場合 | 実装が簡単で設定が分かりやすい |
| ScheduledExecutorService | Springを使わずJava標準で制御したい場合 | 柔軟性が高い |
| Quartz | 複雑なジョブ管理が必要な場合 | 永続化や複数ジョブ管理に向く |
| OSのcronやタスクスケジューラ | アプリ外で実行管理したい場合 | アプリ停止時の影響範囲を分離しやすい |
Spring Bootを使っているなら、まずは @Scheduled を選ぶのが分かりやすいです。ただし、定期実行にしただけでは安全ではありません。次のような点まで実装して初めて実運用向けになります。
@Scheduledで毎分実行する時の注意点
Spring Bootで毎分実行する場合、よく使われるのが fixedDelay や cron です。
考え方の違いは次の通りです。
| 設定方法 | 動き | 向いているケース |
|---|---|---|
| fixedDelay | 前回処理終了後、一定時間待って次回実行 | 前回終了基準で安全に回したい場合 |
| fixedRate | 開始時刻ベースで一定間隔実行 | 厳密な間隔重視だが重複に注意 |
| cron | 指定時刻で実行 | 毎分0秒など、時刻を明確にしたい場合 |
毎分ポーリングでは、前回処理が長引く可能性を考えると fixedDelay の方が安全なことが多いです。cronで毎分実行すると、処理が長引いた場合に次回と重なる可能性があります。
たとえば、外部APIが30秒で返る時もあれば70秒かかる時もあるような場合、毎分固定の実行では重複起動の危険があります。これを避けるには、実行方式の選択に加えて排他制御も必要です。
前回処理と重ならないように排他制御を入れる
毎分ポーリングで特に多いトラブルが、前回の処理が終わらないうちに次の処理が始まることです。これが起きると、同じデータを二重登録したり、更新順序が崩れたりします。
対策は次の通りです。
| 対策 | 内容 |
|---|---|
| 単一スレッド実行 | 同時実行そのものを防ぐ |
| DBやRedisでロック | 複数サーバ構成でも排他しやすい |
| 実行中フラグ管理 | シンプルだが異常終了時の扱いに注意 |
| fixedDelay採用 | 次回開始を前回終了基準にする |
単一サーバなら単一スレッドでも対応できますが、複数台構成ではアプリ内フラグだけでは不十分です。その場合はDBロックやRedisロックなど、共有できる排他手段を使った方が安全です。
HTTPクライアントのタイムアウト設定は必須
外部API連携では、タイムアウト未設定がかなり危険です。レスポンスが遅いとスレッドが長時間塞がり、次回実行や他処理へ影響が出ます。
設定しておきたい主な項目は次の通りです。
| 設定 | 意味 | 目安 |
|---|---|---|
| 接続タイムアウト | 接続確立までの待機時間 | 数秒程度 |
| 読み取りタイムアウト | レスポンス受信待機時間 | 数秒~十数秒程度 |
| 書き込みタイムアウト | リクエスト送信待機時間 | 必要に応じて設定 |
Javaでは java.net.http.HttpClient、Apache HttpClient、OkHttp などを使えますが、どれを使う場合でもタイムアウト設定は必須です。
毎分処理だからこそ、1回のAPI呼び出しに何十秒もぶら下がる実装は避けるべきです。1分間隔で回すなら、1回の通信は余裕を持って短く終わる設計にした方が安定します。
リトライは無条件で繰り返さない
APIが失敗した時にすぐ再試行したくなりますが、無条件リトライは危険です。相手側が障害中なのに短時間で何度も叩くと、さらに失敗が増えたり、制限対象になったりします。
リトライ設計では次を決めておきます。
| 項目 | 実装ポイント |
|---|---|
| 対象エラー | 接続失敗、タイムアウト、一時的な5xxなどに限定する |
| 回数 | 1~3回程度に抑える |
| 間隔 | 固定ではなく少し間隔を空ける |
| 非対象 | 400系エラーや認証エラーは原則リトライしない |
たとえば、401 Unauthorized や 403 Forbidden は認証情報や権限の問題であることが多く、何度再試行しても解決しません。逆に一時的な 502 Bad Gateway や 503 Service Unavailable は、短い待機後に再試行で成功する場合があります。
同じデータを二重処理しない仕組みを入れる
毎分ポーリングでは、「新着だけ取得する」仕組みが重要です。これがないと、毎回同じ一覧を取りにいって、同じデータを何度も登録してしまいます。
代表的な方法は次の通りです。
| 方法 | 内容 | 向いているAPI |
|---|---|---|
| 最終取得日時を保存 | 前回取得以降のデータだけ取得する | 更新日時指定ができるAPI |
| 最新IDを保存 | 直近のID以降だけ処理する | 採番済みIDがあるAPI |
| 取得済みキーをDB管理 | 処理済みデータの重複を防ぐ | 一覧取得型API全般 |
| Upsert処理 | 同じキーなら更新扱いにする | 登録先DB制御が可能な場合 |
API側が since や updatedAfter のようなパラメータを持っているなら活用した方が効率的です。なければ、取得後に自社側で重複判定する必要があります。
レート制限とAPI利用規約を確認する
外部APIには、1分あたりの呼び出し回数や1秒あたりの上限が設定されていることがあります。毎分1回だから問題ないと思っていても、複数処理や複数サーバで呼び出すと上限を超える場合があります。
確認したい点は次の通りです。
| 確認項目 | 内容 |
|---|---|
| レートリミット | 1分あたり、1時間あたりの許可回数 |
| 同時接続数 | 並列アクセスの上限 |
| 取得件数制限 | 1回のレスポンス件数上限 |
| 認証方式 | APIキー、Bearerトークン、署名方式など |
| 利用制約 | 本番・検証環境の違い、禁止事項 |
API仕様書に書かれている上限は必ず確認してください。毎分ポーリングは継続的にアクセスする処理なので、短時間のテストでは見えない制限に引っかかることがあります。
ログは成功時も失敗時も残す
運用後に困るのが、「失敗したことは分かるが、何件取れていたか分からない」「何時から異常だったか分からない」という状態です。これを避けるには、成功ログも適切に残す必要があります。
最低限ほしいログ項目は次の通りです。
| ログ項目 | 例 |
|---|---|
| 実行開始時刻 | 2026-03-07 10:00:00 |
| 実行終了時刻 | 2026-03-07 10:00:03 |
| 処理時間 | 3200ms |
| HTTPステータス | 200、503など |
| 取得件数 | 0件、12件など |
| 処理結果 | 成功、再試行後成功、失敗 |
| エラー内容 | タイムアウト、認証エラーなど |
毎分処理は回数が多いため、ログを出しすぎると逆に見づらくなります。info と error の使い分け、必要なら集計監視へ送る設計も重要です。
例外発生時に処理全体を止めない工夫
定期実行処理は、1回失敗しても次回以降を継続できる作りが大切です。例外をそのまま上位へ投げてスケジューラ全体が止まる構成だと、障害復旧まで長時間データが取り込めないことがあります。
そのため、ポーリング処理では次の考え方が有効です。
| 実装方針 | 理由 |
|---|---|
| 例外を補足してログ出力する | 異常内容を調査できるようにするため |
| 失敗時も次回実行へ進める | 一時障害で全停止しないため |
| 致命的エラーだけ通知する | 運用負荷を下げるため |
| 件数0を異常扱いしない | データ未更新の正常ケースがあるため |
「取れなかったらすぐ止める」より、「取れなくても次回で回復できる」方が毎分ポーリングには向いています。
サンプル実装で意識したい流れ
実際の処理フローは、次のような順序で考えると整理しやすいです。
| 手順 | 処理内容 |
|---|---|
| 1 | 排他ロック取得 |
| 2 | 前回取得位置の読込 |
| 3 | API呼び出し |
| 4 | HTTPステータス確認 |
| 5 | レスポンス解析 |
| 6 | 重複判定 |
| 7 | DB登録または更新 |
| 8 | 前回取得位置の更新 |
| 9 | 結果ログ出力 |
| 10 | ロック解除 |
この流れにしておくと、問題が起きた時に「どこで失敗したか」が追いやすくなります。
よくあるアンチパターン
毎分ポーリングで避けたい実装もあります。特に次のパターンは運用で詰まりやすいです。
| アンチパターン | 問題点 |
|---|---|
| タイムアウト未設定 | 通信待ちで処理が詰まる |
| 毎回全件取得 | API負荷と重複処理が増える |
| 無限リトライ | 相手側障害時にさらに悪化する |
| 排他なしのcron | 重複起動しやすい |
| エラーログだけ出す | 正常時の状態が分からない |
| 1件失敗で全件中断 | 一部障害で全体が止まりやすい |
特に「まず動けばよい」という考えで最初に作られた処理ほど、この問題を含みやすいです。後から直すより、最初から入れておいた方が楽です。
毎分ポーリングよりWebhookが向く場合もある
すべてのケースでポーリングが最適とは限りません。外部サービスがWebhookに対応しているなら、イベント発生時だけ通知を受け取る方式の方が効率的な場合があります。
比較すると次のようになります。
| 方式 | 特徴 |
|---|---|
| ポーリング | 実装しやすいが、定期的に問い合わせる必要がある |
| Webhook | 即時性が高く無駄が少ないが、受信側公開や署名検証が必要 |
ただし、社内ネットワークや閉域環境、受信公開が難しい構成ではポーリングの方が現実的です。そのため、Java業務システムでは今でも毎分ポーリングがよく使われます。
よくある質問(Q & A)
- Javaで毎分ポーリングするなら cron と fixedDelay のどちらがよいですか?
-
前回処理が長引く可能性があるなら fixedDelay の方が安全です。毎分ちょうどに動かしたい要件がある場合は cron も使えますが、重複実行を防ぐ排他制御は必須です。
- APIが失敗した時はすぐ再試行した方がよいですか?
-
一時的な通信障害や5xxエラーなら短い間隔での再試行は有効です。ただし、401や403などの認証・権限系エラーは再試行しても解決しないことが多いため、原因を切り分ける方が優先です。
- 毎分取得しているのに同じデータが何度も登録されます。なぜですか?
-
取得済みデータの管理が不足している可能性があります。最終取得日時、最新ID、処理済みキーなどを保持し、DB側でも一意制約やUpsertを活用すると重複防止しやすくなります。
- 取得件数が0件の時はエラー扱いにすべきですか?
-
通常はエラー扱いにしない方が自然です。更新がないだけの正常ケースも多いためです。ただし、普段は毎回データがある業務なら、一定時間0件が続いた時だけ監視対象にする設計は有効です。
- 毎分ポーリングはAPI側に迷惑になりませんか?
-
API仕様のレート制限や利用規約を守っていれば問題ないケースが多いです。ただし、複数サーバや複数ジョブから同じAPIを呼ぶと想定以上の回数になることがあるため、全体回数で確認する必要があります。
まとめ
Javaで外部APIを毎分ポーリングする時は、単純にスケジュール実行するだけでは不十分です。実運用で重要なのは、タイムアウト設定、排他制御、適切な再試行、重複防止、ログ設計を最初から組み込むことです。
特に毎分実行は回数が多いため、1回ごとの小さな不備が運用トラブルとして積み上がりやすいです。逆にいえば、基本ポイントを押さえておけば、安定した連携処理として長く運用しやすくなります。
これから実装する場合は、まず「どう呼ぶか」ではなく、「失敗した時にどう守るか」から設計すると、後で困りにくい記事品質の高い仕組みに仕上がります。

