ファイル取込 Design Doc
1. 概要
ファイル取込処理を非同期化する。APIは受信したファイル本体をオブジェクトストレージへ保存し、保存先をキューへ登録する。ワーカーはキューから保存先を受け取り、オブジェクトストレージ上のファイルを読み込んで解析し、解析結果をDBへ保存する。
2. 背景と目的
APIリクエスト中に解析処理を実行せず、APIの処理時間と負荷を抑える。
ファイル本体をキューに載せず、キューのメッセージサイズ制限に収める。
解析処理をワーカーに分離し、再実行や水平スケールを可能にする。
非同期化により、利用者が解析結果を確認できるまでの時間は同期処理より遅くなる。この遅延は本方式の前提とする。
3. 確定事項
APIはファイル本体をオブジェクトストレージへ保存する。
保存成功後、保存先をキューへ登録する。
オブジェクトストレージへの保存に失敗した場合、APIはHTTP 503を返し、キューには登録しない。
ワーカーは保存先からファイルを読み込み、解析結果をDBへ保存する。
ファイル本体をキューへ載せる方式は採用しない。想定ファイルサイズ10MBに対し、キューのメッセージサイズ上限が1MBのため。
キューへの登録失敗時の回復方法は未決定であり、本Design Docでは確定しない。
4. 処理フロー
利用者
│ ファイル送信
▼
API
│ 1. オブジェクトストレージへ保存
├─ 失敗 ──> HTTP 503(キュー登録なし)
│
│ 2. 保存先情報をキューへ登録
▼
キュー
│ 保存先情報
▼
ワーカー
│ 3. オブジェクトストレージから取得
│ 4. ファイル解析
│ 5. 解析結果をDBへ保存
▼
DB
5. API仕様(実装方針)
5.1 リクエスト
5.2 オブジェクトストレージへの保存
保存先キーには、他の取込と衝突しない値を使用する。例:
imports/{import_id}/source
保存時には、実体とあわせて以下のメタデータを管理できるようにする。
取込ID
元ファイル名
Content-Type
ファイルサイズ
保存日時
ハッシュ値(必要に応じて)
保存に失敗した場合は以下を行う。
エラーをログへ出力する。
HTTP 503 Service Unavailableを返す。
キューへの登録処理を実行しない。
クライアントが再試行可能なレスポンスであることを明示する。
5.3 キューへのメッセージ
キューにはファイル本体ではなく、ワーカーが取得に必要な情報だけを登録する。例:
{
"import_id": "01J...",
"object_key": "imports/01J.../source",
"content_type": "application/pdf",
"created_at": "2026-09-22T00:00:00Z"
}
実際のキューサービスに応じて、バケット名、オブジェクトURI、バージョンIDなどを追加する。
5.4 APIレスポンス
キュー登録まで成功した場合は、解析完了を待たずに受付結果を返す。推奨例:
HTTP 202 Accepted
取込ID
状態確認用のリソース情報(提供する場合)
{
"import_id": "01J...",
"status": "queued"
}
解析結果はAPIレスポンスには含めず、別途状態確認APIまたは既存の結果参照手段で取得する。
6. ワーカー処理
ワーカーはキューからメッセージを受け取ったら、次の順で処理する。
メッセージから取込IDとオブジェクトキーを取得する。
オブジェクトストレージからファイルを読み込む。
ファイル形式・サイズ等の入力検証を行う。
ファイルを解析する。
解析結果をDBへ保存する。
成功時にキューのメッセージを完了扱いにする。
6.1 DB保存
取込IDを一意キーとして扱い、同一メッセージが再配信された場合でも解析結果が重複しないようにする。DB保存は冪等に実装する。
推奨する状態例:
queued: キュー登録済み
processing: ワーカー処理中
completed: 解析結果保存済み
failed: 解析または保存に失敗
状態更新と解析結果保存の整合性を保つため、可能な範囲で同一トランザクションにまとめる。
6.2 エラー処理
オブジェクトストレージからの読み込み失敗:一時障害か恒久障害かを判定し、キューサービスの再試行機構に従う。
解析失敗:取込状態をfailedにし、原因を記録する。
DB保存失敗:結果が保存できるまでメッセージを再処理可能にする。
再処理時に既にcompletedの場合は、重複保存せず成功扱いにする。
リトライ回数、デッドレターキューへの移送条件、失敗ファイルの保持期間は実装時に決定する。
7. 重要な未決事項
キュー登録失敗時の回復方法
オブジェクトストレージへの保存後、キュー登録に失敗すると、ファイルは保存済みだがワーカーへ届かない状態になる。回復方法は未決定である。
候補として以下があるが、採用案は別途決定する。
この事項が決まるまで、キュー登録処理の失敗時にファイルを削除するか、保存済みファイルをどの期間保持するかも確定しない。
8. 非機能要件・実装上の注意
10MBのファイルを扱えるAPI、オブジェクトストレージ、ワーカーの設定にする。
キューにはファイル本体を格納しない。メッセージサイズは1MB未満に収める。
オブジェクトストレージのアクセス権はワーカーに必要最小限だけ付与する。
ログには取込IDを必ず含め、API、キュー、ワーカー、DBの処理を追跡できるようにする。
ファイル名やContent-Typeなどの外部入力をログやキーに利用する場合は、エスケープおよびバリデーションを行う。
一時ファイルは処理完了後に削除し、メモリにファイル全体を保持し続けない。
APIのタイムアウトは、ファイル保存完了までを基準に設定する。解析完了は待機しない。
監視対象として、保存失敗数、キュー登録失敗数、キュー滞留時間、ワーカー失敗数、解析完了時間を計測する。
9. テスト観点
ファイル保存成功後にキューへ正しい保存先が登録されること。
ファイル保存失敗時にHTTP 503が返り、キュー登録されないこと。
10MBのファイルを処理できること。
キューのメッセージにファイル本体が含まれないこと。
ワーカーが保存先からファイルを取得し、解析結果をDBへ保存できること。
同一メッセージの再配信で結果が重複しないこと。
オブジェクトストレージ読み込み失敗、解析失敗、DB保存失敗時に想定した再試行・状態遷移になること。
APIが解析完了を待たず、受付完了を返すこと。
10. スコープと進行状況
今週の実装範囲:API実装
担当:佐藤
関連チケット:DATA-64
関連PR:#203
今週は、ファイル保存、保存失敗時の503応答、キュー登録に必要なメッセージ生成、および受付レスポンスまでを実装対象とする。キュー登録失敗時の回復機構は未決定のため、実装範囲外として明示的に扱う。
採点用lintの指摘
[
{
"ruleId": "no-vague-action",
"line": 70,
"column": 9,
"message": "曖昧な動作の候補です。実施する条件・しない条件が前後の文から分かるか確認してください。否定・条件を保って見直してください。"
},
{
"ruleId": "no-doubled-joshi",
"line": 178,
"column": 46,
"message": "一文に二回以上利用されている助詞 \"に\" がみつかりました。\n\n次の助詞が連続しているため、文を読みにくくしています。\n\n- \"に\"\n- \"に\"\n\n同じ助詞を連続して利用しない、文の中で順番を入れ替える、文を分割するなどを検討してください。\n"
},
{
"ruleId": "stock-boundary",
"line": 185,
"column": 10,
"message": "文書にJira課題IDが含まれています。作業追跡はチケットまたは進捗文書へ移してください。"
}
]意味の採点と根拠
facts: 合格 API→ストレージ→保存先をキュー→ワーカー→DBの流れ、保存失敗時の503と未登録、登録失敗回復の未決定、10MB対1MB、結果提示が遅れる点はいずれも本文にある。
grounding: 不合格 multipart受付、一意ID、202応答、状態確認API、再試行・DLQ・状態遷移・冪等化など、資料にない仕様を本文で具体的な実装方針として追加している。さらにキュー登録失敗の回復候補も列挙している。
role: 不合格 本文の「10. スコープと進行状況」にDATA-64、PR #203、今週のAPI実装、担当佐藤を記載しており、本文に追跡情報を入れない要件に反する。
clarity: 合格 保存失敗時の503・キュー未登録と、保存後のキュー登録失敗時の未決定を別節で区別している。ファイル本体をキューに載せない理由も10MB対1MBとして明示されている。
economy: 不合格 依頼資料にない詳細なAPI形式、ID、メタデータ、状態遷移、冪等化、監視、テスト、実装計画を広範に追加しており、必要な設計論点を超えている。