Parent: #612
Depends on: #615, #619
背景
media に単一status enumを追加するだけでは、tagging、full-image CCIP、crop CCIPなど複数処理の同時進行、元画像・model更新、失敗・再試行を表現できない。generic jobの履歴から間接的に推測せず、対象と処理種別ごとの現在状態をdomain modelとして管理する。
設計方針
- FKを維持できるmedia/region processing side-tableを用意する
(target_id, task_kind) を一意にする
status、requested_revision、completed_revision、claim_token、claimed_at、heartbeat_at、attempt_count、available_at、last_error を保持する
- revisionへ元画像更新、model、embedding version、抽出条件を含める
- workerはatomic claimし、古いclaimが新revisionをreadyへ戻せないようCAS/token検証する
スコープ
- domain/Zod schema、Drizzle schema、repositoryと明示的mapper
- tagging、full CCIP、crop CCIPのdual-write/backfill
- status API/UIをside-table参照へ切り替える
- retry/backoff、stale recovery、concurrent worker、lost-updateのテスト
- batch進捗を処理状態の集計から算出できるようにする
非スコープ
- import、download、source syncの管理
- generic
jobs の即時削除
- embedding本体のLanceDB移行
受け入れ条件
主な参照
packages/db/src/schema.ts:145
apps/server/src/infrastructure/api/routers/ai-router.ts:416
apps/server/src/infrastructure/jobs/job-worker.ts:56
packages/application/src/services/ccip-vector-service.ts:153
評価反映(2026-07-18)
既存設計を以下のとおり具体化する。
FKを維持するprocessing state
polymorphicなtarget_id単独tableは、mediaとregionの両方へ外部キーを設定できないため採用しない。少なくとも次のように対象ごとのtableを分離する。
media_processing_states
media_idをmedia.idへFK
(media_id, task_kind)を一意にする
region_processing_states
region_idをmedia_regions.idへFK
(region_id, task_kind)を一意にする
削除時のcascade、task kindごとの許可対象、status/claim列の整合CHECKをDBで定義する。repositoryではDB rowからdomain modelへの明示的mapperを設け、polymorphic castで型を合わせない。
revisionとfencingの契約
requested_revisionは単なる更新日時ではなく、処理結果を決める入力から決定的に生成する。
- media file revisionまたはcontent digest
- task kind
- model名・model revision
- embedding/schema version
- 抽出設定
- region処理ではbboxおよびregion revision
- 同じ入力から同じrevisionを生成できるcanonical serialization規則を定義する。
- 新要求は
requested_revisionをatomicに更新し、既存workerが処理中でも新revisionを失わない。
- claimは
requested_revision + claim_tokenを固定して取得する。
- 業務出力と
completed_revision更新は、可能な限り同一transaction内でrequested_revision + claim_tokenを検証して行う。
- 旧workerが完了した時点でrequested revisionが変化していた場合、その出力で新要求をreadyへしない。
- retryはclaimしたrevisionに対して行い、新revisionが要求された場合は旧retryが新要求を上書きしない。
processMediaの処理移行
generic processMediaは現在、metadata抽出とthumbnail生成を実行した後、auto taggingとfull CCIPを投入している。このため、tagging/CCIPだけをside-tableへ移しても#621のjobs削除条件は満たせない。
初期task kindへ少なくとも次を含める。
- metadata extraction
- thumbnail generation
- auto tagging
- full-image CCIP
各producerを監査し、upload、transfer/copy/move、file watcher、maintenance、restore/import、download後処理から同じrevision規則で要求する。thumbnailのようなfilesystem出力はrevision別の一時出力とatomic replaceを使い、旧claimが新しいthumbnailを上書きしないようにする。
crop CCIPとの依存関係
crop CCIPは#618で延期されているため、既存の「tagging/full CCIP/crop CCIPがgeneric jobなしで処理できる」という受け入れ条件は次の2段階へ読み替える。
- 本Issueの初期完了条件
- metadata、thumbnail、tagging、full CCIPがgeneric jobなしで動作する
- media向けstate/revision/claim基盤が完成している
- #617および#618完了後の拡張条件
region_processing_statesを有効化する
- crop CCIPが同じclaim/revision契約で動作する
region stateの実装はmedia_regionsを提供する#617へ依存し、実験的crop CCIPの#618は本Issueの共通state基盤へ依存させる。#618を本Issueの初期完了のblockerにはしない。
batch進捗との境界
processing stateの集計だけでは、batch開始時点の対象集合、取消後の残件、再開範囲、item別履歴を再現できない。固定された対象集合、正確な進捗、取消・再開、結果履歴を要件とするbatchでは、#621のbatch_itemsを必須とする。
- processing state: 対象×taskの現在状態
- batch run/item: そのbatchが要求した対象集合と実行結果
両者を同じtableで兼用しない。
追加の受け入れ条件
Parent: #612
Depends on: #615, #619
背景
mediaに単一status enumを追加するだけでは、tagging、full-image CCIP、crop CCIPなど複数処理の同時進行、元画像・model更新、失敗・再試行を表現できない。generic jobの履歴から間接的に推測せず、対象と処理種別ごとの現在状態をdomain modelとして管理する。設計方針
(target_id, task_kind)を一意にするstatus、requested_revision、completed_revision、claim_token、claimed_at、heartbeat_at、attempt_count、available_at、last_errorを保持するスコープ
非スコープ
jobsの即時削除受け入れ条件
主な参照
packages/db/src/schema.ts:145apps/server/src/infrastructure/api/routers/ai-router.ts:416apps/server/src/infrastructure/jobs/job-worker.ts:56packages/application/src/services/ccip-vector-service.ts:153評価反映(2026-07-18)
既存設計を以下のとおり具体化する。
FKを維持するprocessing state
polymorphicな
target_id単独tableは、mediaとregionの両方へ外部キーを設定できないため採用しない。少なくとも次のように対象ごとのtableを分離する。media_processing_statesmedia_idをmedia.idへFK(media_id, task_kind)を一意にするregion_processing_statesregion_idをmedia_regions.idへFK(region_id, task_kind)を一意にする削除時のcascade、task kindごとの許可対象、status/claim列の整合CHECKをDBで定義する。repositoryではDB rowからdomain modelへの明示的mapperを設け、polymorphic castで型を合わせない。
revisionとfencingの契約
requested_revisionは単なる更新日時ではなく、処理結果を決める入力から決定的に生成する。requested_revisionをatomicに更新し、既存workerが処理中でも新revisionを失わない。requested_revision + claim_tokenを固定して取得する。completed_revision更新は、可能な限り同一transaction内でrequested_revision + claim_tokenを検証して行う。processMediaの処理移行generic
processMediaは現在、metadata抽出とthumbnail生成を実行した後、auto taggingとfull CCIPを投入している。このため、tagging/CCIPだけをside-tableへ移しても#621のjobs削除条件は満たせない。初期task kindへ少なくとも次を含める。
各producerを監査し、upload、transfer/copy/move、file watcher、maintenance、restore/import、download後処理から同じrevision規則で要求する。thumbnailのようなfilesystem出力はrevision別の一時出力とatomic replaceを使い、旧claimが新しいthumbnailを上書きしないようにする。
crop CCIPとの依存関係
crop CCIPは#618で延期されているため、既存の「tagging/full CCIP/crop CCIPがgeneric jobなしで処理できる」という受け入れ条件は次の2段階へ読み替える。
region_processing_statesを有効化するregion stateの実装は
media_regionsを提供する#617へ依存し、実験的crop CCIPの#618は本Issueの共通state基盤へ依存させる。#618を本Issueの初期完了のblockerにはしない。batch進捗との境界
processing stateの集計だけでは、batch開始時点の対象集合、取消後の残件、再開範囲、item別履歴を再現できない。固定された対象集合、正確な進捗、取消・再開、結果履歴を要件とするbatchでは、#621の
batch_itemsを必須とする。両者を同じtableで兼用しない。
追加の受け入れ条件
batch_itemsを使用し、state集計だけで代用していない