@@ -27,34 +27,43 @@ final class ClothAIRepositoryImpl: ClothAIRepository {
2727 return Array ( repeating: nil , count: images. count)
2828 }
2929
30- // 2. S3 병렬 업로드 (개별 실패 허용)
31- return await withTaskGroup ( of: ( Int, String? ) . self, returning: [ String ? ] . self) { group in
32- for (index, ( imageData, presignedInfo) ) in zip ( images, presignedInfos) . enumerated ( ) {
33- group. addTask {
34- do {
35- let contentType = S3UploadHelpers . detectFormat ( from: imageData) . contentType
36- try await self . apiService. uploadImageToS3 (
37- presignedUrl: presignedInfo. presignedUrl,
38- imageData: imageData,
39- contentMD5: presignedInfo. md5Hash,
40- contentType: contentType
41- )
42- return ( index, presignedInfo. finalUrl)
43- } catch {
44- #if DEBUG
45- print ( " [ClothAI] S3 업로드 실패 (index: \( index) ): \( error) " )
46- #endif
47- return ( index, nil )
30+ // 2. S3 업로드 (3장씩 청크 분할하여 동시 메모리 제한)
31+ let chunkSize = 3
32+ var results = Array < String ? > ( repeating: nil , count: images. count)
33+ let pairs = Array ( zip ( images, presignedInfos) . enumerated ( ) )
34+
35+ for chunkStart in stride ( from: 0 , to: pairs. count, by: chunkSize) {
36+ let chunkEnd = min ( chunkStart + chunkSize, pairs. count)
37+ let chunk = pairs [ chunkStart..< chunkEnd]
38+
39+ await withTaskGroup ( of: ( Int, String? ) . self) { group in
40+ for (index, ( imageData, presignedInfo) ) in chunk {
41+ group. addTask {
42+ do {
43+ let contentType = S3UploadHelpers . detectFormat ( from: imageData) . contentType
44+ try await self . apiService. uploadImageToS3 (
45+ presignedUrl: presignedInfo. presignedUrl,
46+ imageData: imageData,
47+ contentMD5: presignedInfo. md5Hash,
48+ contentType: contentType
49+ )
50+ return ( index, presignedInfo. finalUrl)
51+ } catch {
52+ #if DEBUG
53+ print ( " [ClothAI] S3 업로드 실패 (index: \( index) ): \( error) " )
54+ #endif
55+ return ( index, nil )
56+ }
4857 }
4958 }
59+ for await (index, url) in group {
60+ results [ index] = url
61+ }
5062 }
51-
52- var results = Array < String ? > ( repeating: nil , count: images. count)
53- for await (index, url) in group {
54- results [ index] = url
55- }
56- return results
63+ // 이 청크의 TaskGroup 종료 → 캡처된 Data 해제 가능
5764 }
65+
66+ return results
5867 }
5968
6069 func extractClothInfo( clothImageUrls: [ String ] ) async throws -> [ ClothAIInfo ] {
0 commit comments