Skip to content

wodup 인입 비동기 잡

한국어 번역본

이 문서는 원문(영어)의 한국어 번역이다. 정본은 원문이며, 계약·게이트 판단이 갈리면 원문을 따른다. 원문: docs/data/wodup-import-async-jobs.md

wodup 인입은 public.wodup_import_batches를 인입 잡 큐로 사용한다.

인입은 일회성이다: 프로바이더 파일은 딱 한 번만 정본이고, 그 뒤로는 앱이 데이터의 주인이다. 재인입은 앱 기능이 아니라 오너가 실행하는 서비스 절차다 — 파이프라인 형상, 4대 불변식, 제거·재인입 런북은 import-pipeline.md을 본다.

흐름

  1. 브라우저가 원본 JSONL을 Supabase Storage에 업로드하고 wodup_import_batches 행을 insert한다. 브라우저가 테이블에 직접 쓰는 것은 이 insert뿐이며, 이후의 모든 상태 변경은 상태 기계 RPC를 거친다.
  2. 브라우저가 업로드 결과를 mark_wodup_import_batch_uploaded_v1(실패 시 mark_wodup_import_batch_failed_v1)로 표시한다. 컬럼 직접 update는 회수됐다.
  3. wodup-start-importbatch_id를 받는다. 호출자 JWT는 anon 클라이언트로 검증하고 DB 작업은 service key로 수행하며, 검증된 user id는 p_user_id 인자로 흐른다.
  4. Edge Function이 enqueue_wodup_import_batch(...)를 호출한다.
  5. 배치 status가 queued가 된다.
  6. Edge Function은 HTTP 202와 큐에 든 배치를 빠르게 반환한다.
  7. Edge Function이 EdgeRuntime.waitUntil(...)wodup-process-import-jobs를 깨운다. start 함수는 무거운 정규화/인입 작업을 소유하지 않는다.
  8. 워커가 start_wodup_import_batch로 배치를 클레임하고, 원본 파일을 내려받아 봉인된 배치 행과 크기/해시를 대조 검증하고, JSONL을 정규화하고, stage_wodup_import_batch로 스테이징하고, import_wodup_batch_to_canonical로 정본 기입한 뒤 같은 배치 행을 갱신한다.
  9. import_wodup_batch_to_canonical(...)은 스테이징된 세션 정체성이 이미 정본에 있으면 거부한다(22023 / conflict_type: import_already_applied) — 이것이 일회성 게이트다. 또한 영향 범위의 통계 갱신 작업을 user_exercise_stats_refresh_jobs에 넣는다.
  10. UI는 status가 completed, completed_with_placeholders, failed가 될 때까지 wodup_import_batches를 폴링한다.

인입된 세션은 앱에서 read-only다: v4 완료 세션 라이터가 source'barbelic'이 아닌 세션을 거부한다 (22023 / conflict_type: imported_session_read_only).

status 계약

wodup_import_batches.status가 잡 수명주기다.

  • uploading: 원본 파일 행을 만드는 중.
  • uploaded: 원본 파일이 존재하고 큐에 넣을 수 있음.
  • queued: 시작 요청이 접수됨. 백그라운드 작업이 돌아야 함.
  • normalizing: 원본 파일을 검증·정규화하는 중.
  • ready: 정규화 완료. 스테이징 행이 정본 기입을 기다림.
  • importing: 스테이징 행을 앱 테이블로 실체화하는 중.
  • completed: placeholder 없이 인입 완료.
  • completed_with_placeholders: 미매핑 provider 키가 오너 스코프 external 종목으로 실체화된 채 인입 완료 (전역 placeholder 2단계는 폐지 — 매핑 실패는 BRID external 계보로 그 자리에서 한 번에 실체화된다).
  • failed: 인입이 종료 에러에 도달함.

브라우저는 start 요청에서 긴 인입 작업을 기다리지 않는다. 잡을 시작하고 배치 행만 폴링한다. 워커는 start 함수, Supabase cron, 또는 미래의 전용 워커 러너가 깨울 수 있다.

오디언스

enqueue_wodup_import_batch · start_wodup_import_batch · stage_wodup_import_batch · import_wodup_batch_to_canonicalservice_role 전용이다. 호출자는 Edge Function뿐이며 브라우저는 부르지 않는다. 워커가 storage를 service_role(BYPASSRLS)로 읽으므로 소유권 가드는 배치 행 자체가 진다: wodup_import_batches_storage_ownership_checkstorage_pathnormalized_storage_path<user_id>/로 시작하도록 강제한다.

재시도 시맨틱

이미 queued인 배치에 wodup-start-import를 다시 불러도 안전하다. DB enqueue 함수는 행을 queued로 유지하고 last_operation_id만 갱신한다.

워커가 중복 기동돼도 start_wodup_import_batch(...)uploaded·queued 배치만 클레임할 수 있다. 이미 normalizing·importing인 배치는 첫 워커의 소유로 남는다.

이미 정본에 도달한 배치의 재실행은 일회성 게이트가 거부한다. 되돌아가는 길은 오너 런북뿐이다: 프로바이더 데이터 전량 제거(remove_import_data_v1) → 보존된 원본으로 배치 requeue(requeue_wodup_import_batch_v1) → 인입 재시작 — import-pipeline.md을 본다.

함수 경계

  • wodup-start-import: 요청 검증, 배치 소유권 확인, 배치 enqueue, 워커 기동.
  • wodup-process-import-jobs: 큐에 든 배치를 클레임해 정규화·스테이징·정본 기입·최종 배치 status 갱신을 수행.
  • _shared/wodup-import-worker.ts: 재사용 가능한 워커 구현 — 미래의 워커 진입점이 인입 알고리즘을 복사하지 않게 한다.

통계 갱신

정본 기입은 브라우저 요청에서 통계를 직접 계산하지 않는다. 영향받는 유저/종목 범위를 user_exercise_stats_refresh_jobs로 보내 통계 작업이 잡 id로 관측·재시도 가능하게 유지한다. 그 큐의 워커 진입점은 stats-process-refresh-jobs Edge Function이며 process_user_exercise_stats_refresh_jobs(...)를 호출한다.