— Webアプリ設計で混同しがちな概念の整理 —
はじめに
YouTube動画の文字起こしやLLM処理のように、時間のかかる処理をWebアプリに組み込むとき、必ず議論になるのが「同期か、非同期か」という設計選択である。


進捗表示「だけ」を比べた表
| 観点 | 同期 + SSE/WebSocket | 非同期ジョブ |
|---|---|---|
| 進捗の表示 | 可能 | 可能 |
| ページ更新耐性 | 弱い | 強い |
| 切断時の安全性 | 低い | 高い |
| 再開・再試行 | 困難 | 容易 |
| 複数ユーザー | スケール困難 | スケール容易 |
| 管理・監視 | ほぼ不可 | 可能 |
本記事では、
- 同期処理とは何か
- 非同期処理とは何か
- 「ジョブキュー型の非同期」と「async/await(イベントループ)」の違い
- なぜ進捗表示が“できる/できない”ではなく“壊れやすさ”の問題になるのか
を、実装イメージと責務の違いに注目して整理する。
同期処理とは何か
同期処理の本質は、
呼び出し元が、処理の完了まで責任を持つ
という点にある。
典型的な同期処理
def main():
extract_audio()
transcribe()
refine()
export()
main()がすべての処理を順番に実行- 1つの処理が終わるまで次に進まない
- Webアプリの場合、HTTPリクエストが開いている間ずっと処理が続く
同期処理の特徴
- 実装はシンプル
- 処理の流れが直感的
- ただし
- 処理が長いとタイムアウトしやすい
- サーバリソースを占有し続ける
- 接続が切れた瞬間に結果が失われやすい
同期でも進捗表示は可能か?
結論から言えば、可能である。
同期 + 進捗表示の典型手法
- Server-Sent Events(SSE)
- WebSocket
これにより、
- 「音声抽出中」
- 「文字起こし中」
といったステータスを逐次フロントに送ることはできる。
しかし、問題はここではない
同期処理の本質的な弱点は、
- 進捗が「そのHTTP接続にぶら下がっている」
- 接続が切れた瞬間に、ユーザー視点では処理が消える
- 再接続しても途中状態を確認できない
つまり問題は、
表示できるかどうかではなく、状態がどこに存在するか
である。
非同期処理とは何か(ジョブキュー型)
Webアプリで言う「非同期」とは、多くの場合、
処理の実行責任を、main(HTTPリクエスト)から切り離す
ことを意味する。
非同期(ジョブキュー型)の構造
def main():
job_id = enqueue_job(youtube_url)
return job_id
main()は処理を実行しない- 「仕事を登録する」だけで即レスポンス
- 実際の処理は 別のワーカー が実行
構成要素
- ジョブキュー(例:Redis)
- ワーカープロセス
- ジョブ管理DB(状態・進捗・エラー)
非同期処理の本質
- 処理はHTTP接続と無関係に継続
- 状態はDBに永続化される
- ブラウザを閉じても処理は続く
非同期では進捗表示がどう変わるか
非同期では、進捗は「送られる情報」ではなく、
保存された状態を、取りに行く情報
になる。
job_id: 123
status: transcribing
progress: 62%
current_step: whisper
フロントエンドは、
- ポーリング
- WebSocket
などで、この状態を取得して表示する。
結果として可能になること
- ページ更新後も進捗確認可能
- 別端末から進捗確認可能
- 失敗時の原因分析・再実行が容易
- 管理画面で全ジョブを俯瞰可能
async / await(イベントループ)は別物
ここで混同されがちなのが async / await である。
async / await の本質
await は、
処理を待つが、スレッドをブロックしない
という「待ち方」の指定である。
async def job():
audio = await extract_audio()
text = await transcribe(audio)
refined = await refine(text)
- 処理順はシーケンシャル
- しかしI/O待ち中はCPUを解放
- 複数タスクを効率よく捌ける
重要な注意点
async/await≠ 非同期ジョブasync/await≠ 並列実行async/awaitは 単一プロセス内の効率化
概念の整理表
| 概念 | 意味 |
|---|---|
| 同期 | 呼び出し元が完了まで責任を持つ |
| 非同期(ジョブ) | 実行責任を別プロセスに委譲 |
| async / await | 非ブロッキングな待ち方 |
| 並列 | 同時にCPU/GPUを使用 |
| プロセス | OSレベルの実行単位 |
YouTube文字起こし系プロダクトへの適用
この種のプロダクトでは、
- 処理時間が長い
- 成功/失敗の分岐が多い
- 再利用(再Q&A・再エクスポート)が多い
という特性がある。
推奨構成
- Web層:軽量(同期 or async)
- 重処理:非同期ジョブ(ワーカー)
- ジョブ内部:
async/awaitで順序制御
すなわち、
非同期ジョブ × async/await
が最も壊れにくく、拡張しやすい設計となる。
まとめ
- 同期でも進捗表示はできる
- しかし「壊れにくさ」「再開性」「運用性」は非同期が圧倒的に有利
- async/await は非同期処理そのものではなく、効率的な実装手段
非同期を選ぶ理由は「かっこいいから」ではない。
長時間・不確実・再利用前提の処理を、プロダクトとして成立させるためである。


コメント