fix(visionA-backend): DownloadStream 移除 dead ensurePromoted call (Bug #11)
ADR-016 v0.6 後 visionA download 直接從 converter MinIO 拿 NEF、不需先 promote 推上 FAA; 原 Phase 0.8 / v0.4-v0.5 設計的 ensurePromoted 是 dead call。 stage e2e 證實: - visionA DownloadStream → f.ensurePromoted → converter.Promote - converter Promote → faa.putFile (OAuthClientError 401 — converter↔FAA OAuth 鏈獨立 bug) - converter Promote 回 500、visionA DownloadStream 因 ensurePromoted 失敗回 502 - user 看到下載失敗 修法:flow.go DownloadStream 移除 ensurePromoted call、直接 GetResult(converter MinIO 已在 worker `_upload_output` 寫進 NEF、不需 promote 把 NEF 推 FAA)。 PromoteToModels(line 531)流程仍會呼叫 Promote、這是「加到模型庫」的合理步驟、不動。 驗證: - 17 packages race -count=3 全綠 - 新 test TestDownloadStream_DoesNotCallPromote 取代舊 TestDownloadStream_PromoteError_Propagation (故意把 promoteFunc 設成 t.Fatalf、確保 download path 完全不打 promote) 關聯 follow-up(未在本 commit 修): - converter↔FAA OAuth 401 仍是 promote-to-models 流程的 bug、需 converter / MC scope debug - 但 download 解耦後 user 至少能下載 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
78c1343e9a
commit
2d629f3ba2
@ -756,15 +756,20 @@ func (f *flow) DownloadStream(ctx context.Context, userID, jobID string) (io.Rea
|
|||||||
return nil, nil, fmt.Errorf("%w: status=%s", ErrJobNotCompleted, cj.Status)
|
return nil, nil, fmt.Errorf("%w: status=%s", ErrJobNotCompleted, cj.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. ensurePromoted — 自動觸發 promote 確保 converter MinIO 內有 NEF(converter 端冪等)
|
// 2026-05-18 Bug #11 移除 ensurePromoted call:
|
||||||
// 回傳的 targetObjectKey 在 v0.6 只用於 log(visionA 端不再用它打 FAA)
|
// 原 Phase 0.8 / v0.4-v0.5 設計需要先 promote(拿 target_object_key for FAA path)
|
||||||
targetObjectKey, err := f.ensurePromoted(ctx, userID, jobID, cj)
|
// 再 stream from FAA。v0.6 + ADR-016 後 visionA 直接從 converter MinIO 拿、不再
|
||||||
if err != nil {
|
// 走 FAA、target_object_key 無用、ensurePromoted 是 dead call。
|
||||||
return nil, nil, err
|
// 實際 stage e2e 也證實:converter promote → FAA put 撞 OAuth 401(converter ↔ FAA
|
||||||
}
|
// OAuth 鏈獨立 bug、跟 download 不該綁),visionA download 卡 502。
|
||||||
|
// download 直接 GetResult 即可——converter MinIO 在 worker 跑完 nef stage 就有 NEF
|
||||||
|
// (worker `_upload_output` line 121)、不需要 promote。
|
||||||
|
//
|
||||||
|
// PromoteToModels 流程仍會呼叫 ensurePromoted(line 603 直接呼叫 f.converter.Promote)、
|
||||||
|
// 這是「加到模型庫」流程的合理步驟、本次不動。
|
||||||
|
|
||||||
// 4. converter.GetResult — 從 converter MinIO streaming pull NEF
|
// 3. converter.GetResult — 從 converter MinIO streaming pull NEF
|
||||||
// (v0.6:取代原 faa.GetFile(targetObjectKey);visionA 端不再直接打 FAA)
|
// (v0.6:取代原 faa.GetFile;visionA 端完全不打 FAA)
|
||||||
stream, resultMeta, err := f.converter.GetResult(ctx, jobID)
|
stream, resultMeta, err := f.converter.GetResult(ctx, jobID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -786,10 +791,11 @@ func (f *flow) DownloadStream(ctx context.Context, userID, jobID string) (io.Rea
|
|||||||
ContentLength: resultMeta.ContentLength,
|
ContentLength: resultMeta.ContentLength,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2026-05-18 Bug #11:原 log 含 hashObjectKey(targetObjectKey) — Bug #11 移除
|
||||||
|
// ensurePromoted 後 targetObjectKey 不再可用;改記 job_id(已可 cross-ref)+ meta info。
|
||||||
f.logger.InfoContext(ctx, "conversion.flow.download_stream_opened",
|
f.logger.InfoContext(ctx, "conversion.flow.download_stream_opened",
|
||||||
slog.String("user_hash", hashUserID(userID)),
|
slog.String("user_hash", hashUserID(userID)),
|
||||||
slog.String("job_id", jobID),
|
slog.String("job_id", jobID),
|
||||||
slog.String("object_key_hash", hashObjectKey(targetObjectKey)),
|
|
||||||
slog.Int64("content_length", resultMeta.ContentLength),
|
slog.Int64("content_length", resultMeta.ContentLength),
|
||||||
slog.String("filename", meta.Filename),
|
slog.String("filename", meta.Filename),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1220,24 +1220,31 @@ func TestDownloadStream_JobNotCompleted(t *testing.T) {
|
|||||||
assert.Nil(t, meta)
|
assert.Nil(t, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestDownloadStream_PromoteError_Propagation:promote 5xx 透傳。
|
// TestDownloadStream_DoesNotCallPromote:2026-05-18 Bug #11 後 download 不再呼叫 converter.Promote。
|
||||||
func TestDownloadStream_PromoteError_Propagation(t *testing.T) {
|
// 設計理由:ADR-016 v0.6 後 visionA download 直接從 converter MinIO 拿 NEF、不需先 promote 推上 FAA;
|
||||||
|
// ensurePromoted 是 dead call。
|
||||||
|
// 此 test 故意把 promoteFunc 設成 fail——download 不該打到、test 仍應成功(GetResult 走完)。
|
||||||
|
func TestDownloadStream_DoesNotCallPromote(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
fix := newFlowFixture(t)
|
fix := newFlowFixture(t)
|
||||||
|
|
||||||
fix.converter.setJob(&ConverterJob{JobID: "j1", Status: "completed", CreatedAt: time.Now()})
|
fix.converter.setJob(&ConverterJob{JobID: "j1", Status: "completed", CreatedAt: time.Now()})
|
||||||
fix.ownership.Set("j1", "user-alice")
|
fix.ownership.Set("j1", "user-alice")
|
||||||
|
// 故意把 promote 設成 fail——download 不該打到、test 應該仍成功
|
||||||
fix.converter.promoteFunc = func(ctx context.Context, jobID string, req PromoteReq) (*ConverterPromoteResult, error) {
|
fix.converter.promoteFunc = func(ctx context.Context, jobID string, req PromoteReq) (*ConverterPromoteResult, error) {
|
||||||
return nil, fmt.Errorf("%w: promote 502", ErrConverterUnavailable)
|
t.Fatalf("download 不該呼叫 promote (Bug #11 已移除 ensurePromoted)")
|
||||||
|
return nil, errors.New("unreachable")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err := fix.svc.DownloadStream(context.Background(), "user-alice", "j1")
|
stream, meta, err := fix.svc.DownloadStream(context.Background(), "user-alice", "j1")
|
||||||
require.Error(t, err)
|
require.NoError(t, err)
|
||||||
assert.True(t, errors.Is(err, ErrConverterUnavailable))
|
require.NotNil(t, stream)
|
||||||
|
require.NotNil(t, meta)
|
||||||
|
_ = stream.Close()
|
||||||
|
|
||||||
// converter.GetResult 不該被打到(promote 失敗在 GetResult 之前)
|
// converter.GetResult 應該被打到 1 次(promote 沒被打、直接 GetResult)
|
||||||
assert.Equal(t, int32(0), fix.converter.getResultCalls.Load(),
|
assert.Equal(t, int32(1), fix.converter.getResultCalls.Load(),
|
||||||
"promote 失敗應在 converter.GetResult 之前短路")
|
"download 應直接 GetResult、不繞 promote")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestDownloadStream_ConverterGetResultError_Propagation:converter.GetResult 5xx 透傳
|
// TestDownloadStream_ConverterGetResultError_Propagation:converter.GetResult 5xx 透傳
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user