ロングポーリング
サーバーがデータの準備ができるまでレスポンスを保留し、擬似的なリアルタイム通信を実現する手法
ロングポーリングとは
ロングポーリング (Long Polling) は、クライアントがサーバーにリクエストを送り、サーバーがデータの準備ができるまでレスポンスを保留する手法である。通常のポーリング (短いポーリング) が定期的にリクエストを繰り返すのに対し、ロングポーリングはサーバー側でイベントが発生するまで接続を維持する。
通常のポーリングとの比較
通常のポーリングはデータの有無にかかわらず即座にレスポンスを返すため、データがない間も無駄なリクエストが繰り返される。ロングポーリングはサーバーがデータの到着まで接続を保持し、データが来た時点でレスポンスを返す。これにより無駄なリクエストが減り、リアルタイム性も向上する。
短いポーリング:
クライアント → リクエスト → サーバー (データなし → 即座に空レスポンス)
クライアント → リクエスト → サーバー (データなし → 即座に空レスポンス)
クライアント → リクエスト → サーバー (データあり → レスポンス)
ロングポーリング:
クライアント → リクエスト → サーバー (データが来るまで保留...)
(データあり → レスポンス)
クライアント → 即座に再リクエスト → サーバー (保留...)
リアルタイム通信手法の比較
選定の軸は、通信の方向・レイテンシ・実装の複雑さ・サーバーが抱える保留接続の量である。ロングポーリングは「短いポーリングよりレイテンシが小さく、WebSocket より実装が軽い」中間解として位置付けられる。
| 手法 | 方向 | レイテンシ | 複雑さ | サーバー負荷 |
|---|---|---|---|---|
| 短いポーリング | クライアント → サーバー | 高い (間隔依存) | 低い | 高い (空リクエスト多数) |
| ロングポーリング | 擬似双方向 | 中程度 | 中程度 | 中程度 |
| SSE | サーバー → クライアント | 低い | 低い | 低い |
| WebSocket | 双方向 | 最低 | 高い | 低い |
クライアント側の実装
クライアント側の要点は 3 つある。レスポンスを受け取ったら間を置かず次のリクエストを出すこと、タイムアウトと通信エラーを区別すること、エラーのときだけ待ってから再接続することである。区別せず一律で待つと通知が遅れ、一律で即再接続するとサーバー障害時にリクエストが集中する。
async function longPoll(url: string) {
while (true) {
try {
const response = await fetch(url, {
signal: AbortSignal.timeout(30000), // 30秒タイムアウト
});
const data = await response.json();
handleData(data);
} catch (error) {
if (error instanceof DOMException && error.name === 'TimeoutError') {
continue; // タイムアウト → 再接続
}
await new Promise(r => setTimeout(r, 3000)); // エラー → 3秒待って再接続
}
}
}
サーバー側の実装
サーバー側は、保留を打ち切る時刻をクライアントのタイムアウトより短くするのが定石である。逆にするとクライアントが先に接続を切り、サーバーは戻す先を失ったまま待ち続ける。さらに、打ち切りとデータ到着が競合したときにレスポンスを二重送信しないガードが必要になる。
app.get('/api/notifications', async (req, res) => {
let sent = false;
const send = (payload: unknown) => {
if (sent) return; // 二重送信を防ぐ
sent = true;
res.json(payload);
};
// クライアント側の 30 秒より先に打ち切る
const timeout = setTimeout(() => send({ data: null }), 25000);
try {
const data = await waitForNewData(req.query.lastId); // データが来るまで待機
send({ data });
} finally {
clearTimeout(timeout);
}
});
クライアントが前回受け取った位置 (上の例では lastId) を毎回送っているのも必須の作りである。レスポンスを返してから次のリクエストが届くまでにはわずかな隙間があり、その間に起きたイベントは位置情報が無いと消える。
Lambda での制約
Lambda 関数自体は最大 900 秒 (15 分) 動かせる。ロングポーリングで先に壁になるのは前段の API Gateway 側で、REST API の統合タイムアウトは既定 29 秒、設定できる範囲は 50 ミリ秒から 29,000 ミリ秒である。2026 年 8 月時点ではサービスクォータの引き上げ申請によって 29 秒を超える値も設定できるが、対象はリージョン別 REST API とプライベート REST API に限られ、アカウントのスロットリング上限の引き下げを求められる場合がある。HTTP API の統合タイムアウトは 30 秒が上限で、こちらは引き上げできない。「Lambda が 29 秒しか待てない」と覚えると障害の切り分けを誤るので、制約がどちら側にあるかを分けて把握しておく。
保留している時間がそのまま関数の実行時間になる点も見落としやすい。Lambda の課金はコードが動き始めてから終わる (または停止する) までの時間を 1 ミリ秒単位に切り上げて計算するため、待っているだけの時間にも料金が発生する。常時接続に近い使い方をしたいなら、次の選択肢を検討する。
- API Gateway WebSocket API: 双方向通信ができる。ただし 1 接続の維持は最大 2 時間、無通信が続くと 10 分で切断されるため、クライアント側の再接続実装が前提になる。
- AppSync Subscriptions: GraphQL の購読としてリアルタイム通知を実現する。接続の管理をサービス側に寄せられる。
- SQS: クライアントから直接ではなくバックエンドがキューを読む構成にする。SQS 自体が受信待機時間として最大 20 秒のロングポーリングを備えており (待機時間 0 秒に設定したときだけ短いポーリングになる)、AWS も多くの場合 20 秒を推奨している。
使うべきケース
- WebSocket や SSE が使えない環境 (プロキシ制限、古いブラウザ)
- シンプルな通知機能で、WebSocket ほどの双方向通信が不要
- 既存の HTTP インフラをそのまま使いたい場合
ロングポーリングの理解を深めるには関連書籍が参考になる。
この記事は役に立ちましたか?
関連用語
WebSocket API
API Gateway の WebSocket API でサーバーレスなリアルタイム双方向通信を実現する仕組み
Fetch API
HTTP リクエストを送信するためのモダンな Web API で、XMLHttpRequest の後継
GraphQL Subscription
GraphQL でサーバーからクライアントへリアルタイムデータ更新を配信する仕組み
Webhook
イベント発生時にサーバーが指定された URL に HTTP リクエストを送信する、プッシュ型の通知メカニズム
WebSocket
クライアントとサーバー間で双方向のリアルタイム通信を実現するプロトコル
SSE (Server-Sent Events) とは - サーバーからのリアルタイム配信の仕組み
SSE はサーバーからクライアントへ HTTP 上で一方向のリアルタイムストリームを送る仕組み。WebSocket との違い・EventSource API の使い方・再接続処理を解説
関連する記事
あなたの「積ん読」は投資ポートフォリオである
積ん読を罪悪感の対象ではなく、知識への分散投資として捉え直す視点を提案します。積ん読の戦略的な管理方法と、必要なときに引き出す仕組みづくり。
本についてくるダウンロード素材を使い倒す
プログラミングの本には、サンプルコードや練習用データのダウンロード特典がついていることがあります。素材の探し方と、完成版コードの使い方を解説します。
IT パスポート参考書の選び方 - 完読できる 1 冊と過去問の組み合わせ
IT パスポート試験の参考書選びを「完読できるか」を軸に整理。イラスト型 / 絞り込み型 / 丁寧解説型などテキストの個性の見分け方、過去問題集との組み合わせ、年度版とシラバス対応の注意点を 2026 年 8 月時点の定番書で解説します。