synapse-sdk 2025.9.5__py3-none-any.whl → 2025.10.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of synapse-sdk might be problematic. Click here for more details.

Files changed (78) hide show
  1. synapse_sdk/clients/base.py +129 -9
  2. synapse_sdk/devtools/docs/docs/api/clients/base.md +230 -8
  3. synapse_sdk/devtools/docs/docs/api/plugins/models.md +58 -3
  4. synapse_sdk/devtools/docs/docs/plugins/categories/neural-net-plugins/train-action-overview.md +663 -0
  5. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
  6. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
  7. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
  8. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
  9. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-action.md +934 -0
  10. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-overview.md +585 -0
  11. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-template.md +715 -0
  12. synapse_sdk/devtools/docs/docs/plugins/export-plugins.md +39 -0
  13. synapse_sdk/devtools/docs/docs/plugins/plugins.md +12 -5
  14. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/base.md +230 -8
  15. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/plugins/models.md +114 -0
  16. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/neural-net-plugins/train-action-overview.md +621 -0
  17. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
  18. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
  19. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
  20. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
  21. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-action.md +934 -0
  22. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-overview.md +585 -0
  23. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-template.md +715 -0
  24. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/export-plugins.md +39 -0
  25. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current.json +16 -4
  26. synapse_sdk/devtools/docs/sidebars.ts +45 -1
  27. synapse_sdk/plugins/README.md +487 -80
  28. synapse_sdk/plugins/categories/base.py +1 -0
  29. synapse_sdk/plugins/categories/export/actions/export/action.py +8 -3
  30. synapse_sdk/plugins/categories/export/actions/export/utils.py +108 -8
  31. synapse_sdk/plugins/categories/export/templates/config.yaml +18 -0
  32. synapse_sdk/plugins/categories/export/templates/plugin/export.py +97 -0
  33. synapse_sdk/plugins/categories/neural_net/actions/train.py +592 -22
  34. synapse_sdk/plugins/categories/neural_net/actions/tune.py +150 -3
  35. synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +4 -0
  36. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/__init__.py +3 -0
  37. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/action.py +10 -0
  38. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/__init__.py +28 -0
  39. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/action.py +145 -0
  40. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/enums.py +269 -0
  41. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/exceptions.py +14 -0
  42. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/factory.py +76 -0
  43. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/models.py +97 -0
  44. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/orchestrator.py +250 -0
  45. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/run.py +64 -0
  46. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/__init__.py +17 -0
  47. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/annotation.py +284 -0
  48. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/base.py +170 -0
  49. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/extraction.py +83 -0
  50. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/metrics.py +87 -0
  51. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/preprocessor.py +127 -0
  52. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/validation.py +143 -0
  53. synapse_sdk/plugins/categories/upload/actions/upload/__init__.py +2 -1
  54. synapse_sdk/plugins/categories/upload/actions/upload/action.py +8 -1
  55. synapse_sdk/plugins/categories/upload/actions/upload/context.py +0 -1
  56. synapse_sdk/plugins/categories/upload/actions/upload/models.py +134 -94
  57. synapse_sdk/plugins/categories/upload/actions/upload/steps/cleanup.py +2 -2
  58. synapse_sdk/plugins/categories/upload/actions/upload/steps/generate.py +6 -2
  59. synapse_sdk/plugins/categories/upload/actions/upload/steps/initialize.py +24 -9
  60. synapse_sdk/plugins/categories/upload/actions/upload/steps/metadata.py +130 -18
  61. synapse_sdk/plugins/categories/upload/actions/upload/steps/organize.py +147 -37
  62. synapse_sdk/plugins/categories/upload/actions/upload/steps/upload.py +10 -5
  63. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/flat.py +31 -6
  64. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/recursive.py +65 -37
  65. synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/default.py +17 -2
  66. synapse_sdk/plugins/categories/upload/templates/README.md +394 -0
  67. synapse_sdk/plugins/models.py +62 -0
  68. synapse_sdk/utils/file/download.py +261 -0
  69. {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/METADATA +15 -2
  70. {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/RECORD +74 -43
  71. synapse_sdk/devtools/docs/docs/plugins/developing-upload-template.md +0 -1463
  72. synapse_sdk/devtools/docs/docs/plugins/upload-plugins.md +0 -1964
  73. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/developing-upload-template.md +0 -1463
  74. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/upload-plugins.md +0 -2077
  75. {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/WHEEL +0 -0
  76. {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/entry_points.txt +0 -0
  77. {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/licenses/LICENSE +0 -0
  78. {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/top_level.txt +0 -0
@@ -1,2077 +0,0 @@
1
- ---
2
- id: upload-plugins
3
- title: 업로드 플러그인
4
- sidebar_position: 3
5
- ---
6
-
7
- # 업로드 플러그인
8
-
9
- 업로드 플러그인은 포괄적인 메타데이터 지원, 보안 검증 및 체계적인 데이터 단위 생성을 통해 파일을 Synapse 플랫폼으로 처리하기 위한 파일 업로드 및 데이터 수집 작업을 제공합니다.
10
-
11
- ## 개요
12
-
13
- **사용 가능한 액션:**
14
-
15
- - `upload` - 선택적 Excel 메타데이터 처리를 통한 파일 및 디렉토리 스토리지 업로드
16
-
17
- **사용 사례:**
18
-
19
- - 메타데이터 주석을 포함한 대량 파일 업로드
20
- - Excel 기반 메타데이터 매핑 및 검증
21
- - 재귀적 디렉토리 처리
22
- - 타입 기반 파일 구성
23
- - 배치 데이터 단위 생성
24
- - 크기 및 내용 검증을 통한 안전한 파일 처리
25
-
26
- **지원되는 업로드 소스:**
27
-
28
- - 로컬 파일 시스템 경로 (파일 및 디렉토리)
29
- - 재귀적 디렉토리 스캔
30
- - 향상된 파일 주석을 위한 Excel 메타데이터 파일
31
- - 자동 구성을 통한 혼합 파일 타입
32
-
33
- ## 업로드 액션 아키텍처
34
-
35
- 업로드 시스템은 검증된 디자인 패턴을 기반으로 구축된 현대적이고 확장 가능한 아키텍처를 사용합니다. 리팩토링된 구현은 이전의 모놀리식 접근 방식을 관심사의 명확한 분리가 있는 모듈식 전략 기반 시스템으로 변환합니다.
36
-
37
- ### 디자인 패턴
38
-
39
- 아키텍처는 여러 핵심 디자인 패턴을 활용합니다:
40
-
41
- - **전략 패턴**: 검증, 파일 발견, 메타데이터 처리, 업로드 작업 및 데이터 단위 생성을 위한 플러그형 동작
42
- - **파사드 패턴**: UploadOrchestrator는 복잡한 워크플로우를 조정하기 위한 단순화된 인터페이스를 제공
43
- - **팩토리 패턴**: StrategyFactory는 런타임 매개변수를 기반으로 적절한 전략 구현을 생성
44
- - **컨텍스트 패턴**: UploadContext는 워크플로우 구성 요소 간의 공유 상태 및 통신을 유지
45
-
46
- ### 컴포넌트 아키텍처
47
-
48
- ```mermaid
49
- classDiagram
50
- %% Light/Dark mode compatible colors
51
- classDef coreClass fill:#e3f2fd,stroke:#1976d2,stroke-width:2px,color:#000000
52
- classDef strategyClass fill:#e8f5e8,stroke:#388e3c,stroke-width:2px,color:#000000
53
- classDef stepClass fill:#fff9c4,stroke:#f57c00,stroke-width:2px,color:#000000
54
- classDef contextClass fill:#ffebee,stroke:#d32f2f,stroke-width:2px,color:#000000
55
-
56
- class UploadAction {
57
- +name: str = "upload"
58
- +category: PluginCategory.UPLOAD
59
- +method: RunMethod.JOB
60
- +run_class: UploadRun
61
- +params_model: UploadParams
62
- +strategy_factory: StrategyFactory
63
- +step_registry: StepRegistry
64
-
65
- +start() dict
66
- +get_workflow_summary() dict
67
- +_configure_workflow() None
68
- +_configure_strategies() dict
69
- }
70
-
71
- class UploadOrchestrator {
72
- +context: UploadContext
73
- +step_registry: StepRegistry
74
- +strategies: dict
75
- +executed_steps: list
76
- +current_step_index: int
77
- +rollback_executed: bool
78
-
79
- +execute() dict
80
- +get_workflow_summary() dict
81
- +get_executed_steps() list
82
- +is_rollback_executed() bool
83
- +_execute_step(step) StepResult
84
- +_handle_step_failure(step, error) None
85
- +_rollback_executed_steps() None
86
- }
87
-
88
- class UploadContext {
89
- +params: dict
90
- +run: UploadRun
91
- +client: Any
92
- +storage: Any
93
- +pathlib_cwd: Path
94
- +metadata: dict
95
- +file_specifications: dict
96
- +organized_files: list
97
- +uploaded_files: list
98
- +data_units: list
99
- +metrics: dict
100
- +errors: list
101
- +strategies: dict
102
- +rollback_data: dict
103
-
104
- +update(result: StepResult) None
105
- +get_result() dict
106
- +has_errors() bool
107
- +update_metrics(category, metrics) None
108
- }
109
-
110
- class StepRegistry {
111
- +_steps: list
112
- +register(step: BaseStep) None
113
- +get_steps() list
114
- +get_total_progress_weight() float
115
- +clear() None
116
- }
117
-
118
- class StrategyFactory {
119
- +create_validation_strategy(params, context) BaseValidationStrategy
120
- +create_file_discovery_strategy(params, context) BaseFileDiscoveryStrategy
121
- +create_metadata_strategy(params, context) BaseMetadataStrategy
122
- +create_upload_strategy(params, context) BaseUploadStrategy
123
- +create_data_unit_strategy(params, context) BaseDataUnitStrategy
124
- +get_available_strategies() dict
125
- }
126
-
127
- class BaseStep {
128
- <<abstract>>
129
- +name: str
130
- +progress_weight: float
131
- +execute(context: UploadContext) StepResult
132
- +can_skip(context: UploadContext) bool
133
- +rollback(context: UploadContext) None
134
- +create_success_result(data) StepResult
135
- +create_error_result(error) StepResult
136
- +create_skip_result() StepResult
137
- }
138
-
139
- class StepResult {
140
- +success: bool
141
- +data: dict
142
- +error: str
143
- +rollback_data: dict
144
- +skipped: bool
145
- +original_exception: Exception
146
- +timestamp: datetime
147
- }
148
-
149
- %% Strategy Base Classes
150
- class BaseValidationStrategy {
151
- <<abstract>>
152
- +validate_files(files, context) bool
153
- +validate_security(file_path) bool
154
- }
155
-
156
- class BaseFileDiscoveryStrategy {
157
- <<abstract>>
158
- +discover_files(path, context) list
159
- +organize_files(files, specs, context) list
160
- }
161
-
162
- class BaseMetadataStrategy {
163
- <<abstract>>
164
- +process_metadata(context) dict
165
- +extract_metadata(file_path) dict
166
- }
167
-
168
- class BaseUploadStrategy {
169
- <<abstract>>
170
- +upload_files(files, context) list
171
- +upload_batch(batch, context) list
172
- }
173
-
174
- class BaseDataUnitStrategy {
175
- <<abstract>>
176
- +generate_data_units(files, context) list
177
- +create_data_unit_batch(batch, context) list
178
- }
179
-
180
- %% Workflow Steps
181
- class InitializeStep {
182
- +name = "initialize"
183
- +progress_weight = 0.05
184
- }
185
-
186
- class ProcessMetadataStep {
187
- +name = "process_metadata"
188
- +progress_weight = 0.05
189
- }
190
-
191
- class AnalyzeCollectionStep {
192
- +name = "analyze_collection"
193
- +progress_weight = 0.05
194
- }
195
-
196
- class OrganizeFilesStep {
197
- +name = "organize_files"
198
- +progress_weight = 0.10
199
- }
200
-
201
- class ValidateFilesStep {
202
- +name = "validate_files"
203
- +progress_weight = 0.05
204
- }
205
-
206
- class UploadFilesStep {
207
- +name = "upload_files"
208
- +progress_weight = 0.30
209
- }
210
-
211
- class GenerateDataUnitsStep {
212
- +name = "generate_data_units"
213
- +progress_weight = 0.35
214
- }
215
-
216
- class CleanupStep {
217
- +name = "cleanup"
218
- +progress_weight = 0.05
219
- }
220
-
221
- %% Relationships
222
- UploadAction --> UploadOrchestrator : creates and executes
223
- UploadAction --> StrategyFactory : configures strategies
224
- UploadAction --> StepRegistry : manages workflow steps
225
- UploadOrchestrator --> UploadContext : coordinates state
226
- UploadOrchestrator --> StepRegistry : executes steps from
227
- UploadOrchestrator --> BaseStep : executes
228
- BaseStep --> StepResult : returns
229
- UploadContext --> StepResult : updates with
230
- StrategyFactory --> BaseValidationStrategy : creates
231
- StrategyFactory --> BaseFileDiscoveryStrategy : creates
232
- StrategyFactory --> BaseMetadataStrategy : creates
233
- StrategyFactory --> BaseUploadStrategy : creates
234
- StrategyFactory --> BaseDataUnitStrategy : creates
235
- StepRegistry --> BaseStep : contains
236
-
237
- %% Step inheritance
238
- InitializeStep --|> BaseStep : extends
239
- ProcessMetadataStep --|> BaseStep : extends
240
- AnalyzeCollectionStep --|> BaseStep : extends
241
- OrganizeFilesStep --|> BaseStep : extends
242
- ValidateFilesStep --|> BaseStep : extends
243
- UploadFilesStep --|> BaseStep : extends
244
- GenerateDataUnitsStep --|> BaseStep : extends
245
- CleanupStep --|> BaseStep : extends
246
-
247
- %% Note: Class styling defined above - Mermaid will apply based on classDef definitions
248
- ```
249
-
250
- ### 단계 기반 워크플로우 실행
251
-
252
- 리팩토링된 아키텍처는 UploadOrchestrator에 의해 조정되는 단계 기반 워크플로우를 사용합니다. 각 단계는 정의된 책임과 진행률 가중치를 가집니다.
253
-
254
- #### 워크플로우 단계 개요
255
-
256
- | 단계 | 이름 | 가중치 | 책임 |
257
- | ---- | ------------------- | ------ | ---------------------------------- |
258
- | 1 | Initialize | 5% | 스토리지, pathlib, 기본 검증 설정 |
259
- | 2 | Process Metadata | 5% | 제공된 Excel 메타데이터 처리 |
260
- | 3 | Analyze Collection | 5% | 데이터 컬렉션 사양 검색 및 검증 |
261
- | 4 | Organize Files | 10% | 타입별 파일 발견 및 구성 |
262
- | 5 | Validate Files | 5% | 보안 및 내용 검증 |
263
- | 6 | Upload Files | 30% | 스토리지에 파일 업로드 |
264
- | 7 | Generate Data Units | 35% | 업로드된 파일에서 데이터 단위 생성 |
265
- | 8 | Cleanup | 5% | 임시 리소스 정리 |
266
-
267
- #### 실행 플로우
268
-
269
- ```mermaid
270
- flowchart TD
271
- %% Start
272
- A["🚀 업로드 액션 시작"] --> B["📋 UploadContext 생성"]
273
- B --> C["⚙️ 전략 구성"]
274
- C --> D["📝 워크플로우 단계 등록"]
275
- D --> E["🎯 UploadOrchestrator 생성"]
276
-
277
- %% Strategy Injection
278
- E --> F["💉 컨텍스트에 전략 주입"]
279
- F --> G["📊 진행률 추적 초기화"]
280
-
281
- %% Step Execution Loop
282
- G --> H["🔄 단계 실행 루프 시작"]
283
- H --> I["📍 다음 단계 가져오기"]
284
- I --> J{"🤔 단계를 건너뛸 수 있는가?"}
285
- J -->|Yes| K["⏭️ 단계 건너뛰기"]
286
- J -->|No| L["▶️ 단계 실행"]
287
-
288
- %% Step Execution
289
- L --> M{"✅ 단계 성공?"}
290
- M -->|Yes| N["📈 진행률 업데이트"]
291
- M -->|No| O["❌ 단계 실패 처리"]
292
-
293
- %% Success Path
294
- N --> P["💾 단계 결과 저장"]
295
- P --> Q["📝 실행된 단계에 추가"]
296
- Q --> R{"🏁 더 많은 단계?"}
297
- R -->|Yes| I
298
- R -->|No| S["🎉 워크플로우 완료"]
299
-
300
- %% Skip Path
301
- K --> T["📊 진행률 업데이트 (건너뛰기)"]
302
- T --> R
303
-
304
- %% Error Handling
305
- O --> U["🔙 롤백 프로세스 시작"]
306
- U --> V["⏪ 실행된 단계 롤백"]
307
- V --> W["📝 롤백 결과 로그"]
308
- W --> X["💥 예외 전파"]
309
-
310
- %% Final Results
311
- S --> Y["📊 최종 메트릭 수집"]
312
- Y --> Z["📋 결과 요약 생성"]
313
- Z --> AA["🔄 UploadAction으로 반환"]
314
-
315
- %% Apply styles - Light/Dark mode compatible
316
- classDef startNode fill:#e3f2fd,stroke:#1976d2,stroke-width:2px,color:#000000
317
- classDef processNode fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,color:#000000
318
- classDef decisionNode fill:#fff3e0,stroke:#f57c00,stroke-width:2px,color:#000000
319
- classDef successNode fill:#e8f5e8,stroke:#388e3c,stroke-width:2px,color:#000000
320
- classDef errorNode fill:#ffebee,stroke:#d32f2f,stroke-width:2px,color:#000000
321
- classDef stepNode fill:#f0f4c3,stroke:#689f38,stroke-width:1px,color:#000000
322
-
323
- class A,B,E startNode
324
- class C,D,F,G,H,I,L,N,P,Q,T,Y,Z,AA processNode
325
- class J,M,R decisionNode
326
- class K,S successNode
327
- class O,U,V,W,X errorNode
328
- ```
329
-
330
- #### 단계 실행 세부사항
331
-
332
- ```mermaid
333
- flowchart TD
334
- %% Individual Step Details
335
- A["🚀 워크플로우 단계 개요"]
336
-
337
- A --> B1["1. 🏗️ 초기화 단계<br/>가중치: 5%<br/>• 스토리지 연결 설정<br/>• pathlib 액세스 검증<br/>• 컨텍스트 상태 초기화"]
338
- A --> B2["2. 📋 메타데이터 처리 단계<br/>가중치: 5%<br/>• Excel 메타데이터 파싱<br/>• 보안 제약 검증<br/>• 파일명 매핑 생성"]
339
- A --> B3["3. 🔍 컬렉션 분석 단계<br/>가중치: 5%<br/>• 파일 사양 검색<br/>• 컬렉션 접근 검증<br/>• 구성 규칙 설정"]
340
- A --> B4["4. 🗂️ 파일 구성 단계<br/>가중치: 10%<br/>• 파일 발견 (재귀/평면)<br/>• 파일 타입별 그룹화<br/>• 구성된 구조 생성"]
341
- A --> B5["5. ✅ 파일 검증 단계<br/>가중치: 5%<br/>• 보안 검증<br/>• 크기 및 내용 검사<br/>• 검증 전략 적용"]
342
- A --> B6["6. ⬆️ 파일 업로드 단계<br/>가중치: 30%<br/>• 배치 파일 업로드<br/>• 진행률 추적<br/>• 실패한 업로드 재시도"]
343
- A --> B7["7. 🏗️ 데이터 단위 생성 단계<br/>가중치: 35%<br/>• 데이터 단위 생성<br/>• 배치 처리<br/>• 파일을 단위에 연결"]
344
- A --> B8["8. 🧹 정리 단계<br/>가중치: 5%<br/>• 임시 파일 정리<br/>• 리소스 해제<br/>• 최종 검증"]
345
-
346
- %% Step Details
347
- B1 --> C1["책임사항:<br/>• 클라이언트에서 스토리지 가져오기<br/>• pathlib 작업 디렉터리 초기화<br/>• 기본 업로드 전제조건 검증"]
348
- B2 --> C2["책임사항:<br/>• Excel 메타데이터 파일 로드 및 파싱<br/>• 보안 검증 적용<br/>• 파일명-메타데이터 매핑 생성"]
349
- B3 --> C3["책임사항:<br/>• 데이터 컬렉션 사양 가져오기<br/>• 파일 타입 요구사항 검증<br/>• 구성 규칙 설정"]
350
- B4 --> C4["책임사항:<br/>• 파일 발견 전략 사용<br/>• 파일 필터링 및 분류<br/>• 구성된 파일 구조 생성"]
351
- B5 --> C5["책임사항:<br/>• 검증 전략 사용<br/>• 파일 보안 및 내용 검사<br/>• 비즈니스 검증 규칙 적용"]
352
- B6 --> C6["책임사항:<br/>• 업로드 전략 사용<br/>• 구성 가능한 배치로 파일 처리<br/>• 진행률 추적 및 실패 처리"]
353
- B7 --> C7["책임사항:<br/>• 데이터 단위 전략 사용<br/>• 업로드된 파일에서 데이터 단위 생성<br/>• 파일을 적절한 단위에 연결"]
354
- B8 --> C8["책임사항:<br/>• 임시 파일 및 리소스 정리<br/>• 최종 시스템 검증 수행<br/>• 깨끗한 종료 보장"]
355
-
356
- %% Apply styles - Light/Dark mode compatible
357
- classDef overviewNode fill:#e3f2fd,stroke:#1976d2,stroke-width:3px,color:#000000
358
- classDef stepNode fill:#fff9c4,stroke:#f57c00,stroke-width:2px,color:#000000
359
- classDef detailNode fill:#f0f4c3,stroke:#689f38,stroke-width:1px,color:#000000
360
-
361
- class A overviewNode
362
- class B1,B2,B3,B4,B5,B6,B7,B8 stepNode
363
- class C1,C2,C3,C4,C5,C6,C7,C8 detailNode
364
- ```
365
-
366
- #### 전략 통합 지점
367
-
368
- 전략은 워크플로우의 특정 지점에서 주입됩니다:
369
-
370
- - **검증 전략**: ValidateFilesStep에서 사용
371
- - **파일 발견 전략**: OrganizeFilesStep에서 사용
372
- - **메타데이터 전략**: ProcessMetadataStep에서 사용
373
- - **업로드 전략**: UploadFilesStep에서 사용
374
- - **데이터 단위 전략**: GenerateDataUnitsStep에서 사용
375
-
376
- #### 오류 처리 및 롤백
377
-
378
- 오케스트레이터는 자동 롤백 기능을 제공합니다:
379
-
380
- 1. **예외 캡처**: 디버깅을 위해 원본 예외 보존
381
- 2. **롤백 실행**: 성공적으로 실행된 모든 단계에서 역순으로 rollback() 호출
382
- 3. **우아한 저하**: 개별 단계 롤백이 실패해도 롤백 계속 진행
383
- 4. **상태 보존**: 실패 후 분석을 위한 실행 상태 유지
384
-
385
- ## 개발 가이드
386
-
387
- 이 섹션은 사용자 정의 전략과 워크플로우 단계로 업로드 액션을 확장하기 위한 포괄적인 가이드를 제공합니다.
388
-
389
- ### 사용자 정의 전략 생성
390
-
391
- 전략은 업로드 프로세스의 다양한 측면에 대한 특정 동작을 구현합니다. 각 전략 타입은 잘 정의된 인터페이스를 가지고 있습니다.
392
-
393
- #### 사용자 정의 검증 전략
394
-
395
- ```python
396
- from synapse_sdk.plugins.categories.upload.actions.upload.strategies.validation.base import BaseValidationStrategy
397
- from synapse_sdk.plugins.categories.upload.actions.upload.context import UploadContext
398
-
399
- class CustomValidationStrategy(BaseValidationStrategy):
400
- """고급 보안 검사를 포함한 사용자 정의 검증 전략."""
401
-
402
- def validate_files(self, files: List[Path], context: UploadContext) -> bool:
403
- """사용자 정의 비즈니스 규칙을 사용하여 파일 검증."""
404
- for file_path in files:
405
- # 사용자 정의 검증 로직
406
- if not self._validate_custom_rules(file_path):
407
- return False
408
-
409
- # 보안 검증 호출
410
- if not self.validate_security(file_path):
411
- return False
412
- return True
413
-
414
- def validate_security(self, file_path: Path) -> bool:
415
- """사용자 정의 보안 검증."""
416
- # 사용자 정의 보안 검사 구현
417
- if file_path.suffix in ['.exe', '.bat', '.sh']:
418
- return False
419
-
420
- # 파일 크기 검사
421
- if file_path.stat().st_size > 100 * 1024 * 1024: # 100MB
422
- return False
423
-
424
- return True
425
-
426
- def _validate_custom_rules(self, file_path: Path) -> bool:
427
- """도메인별 검증 규칙 구현."""
428
- # 사용자 정의 비즈니스 로직
429
- return True
430
- ```
431
-
432
- #### 사용자 정의 파일 발견 전략
433
-
434
- ```python
435
- from synapse_sdk.plugins.categories.upload.actions.upload.strategies.file_discovery.base import BaseFileDiscoveryStrategy
436
- from pathlib import Path
437
- from typing import List, Dict, Any
438
-
439
- class CustomFileDiscoveryStrategy(BaseFileDiscoveryStrategy):
440
- """고급 필터링을 포함한 사용자 정의 파일 발견."""
441
-
442
- def discover_files(self, path: Path, context: UploadContext) -> List[Path]:
443
- """사용자 정의 필터링 규칙으로 파일 발견."""
444
- files = []
445
-
446
- if context.get_param('is_recursive', False):
447
- files = list(path.rglob('*'))
448
- else:
449
- files = list(path.iterdir())
450
-
451
- # 사용자 정의 필터링 적용
452
- return self._apply_custom_filters(files, context)
453
-
454
- def organize_files(self, files: List[Path], specs: Dict[str, Any], context: UploadContext) -> List[Dict[str, Any]]:
455
- """사용자 정의 분류를 사용하여 파일 구성."""
456
- organized = []
457
-
458
- for file_path in files:
459
- if file_path.is_file():
460
- category = self._determine_category(file_path)
461
- organized.append({
462
- 'file_path': file_path,
463
- 'category': category,
464
- 'metadata': self._extract_file_metadata(file_path)
465
- })
466
-
467
- return organized
468
-
469
- def _apply_custom_filters(self, files: List[Path], context: UploadContext) -> List[Path]:
470
- """도메인별 파일 필터 적용."""
471
- filtered = []
472
- for file_path in files:
473
- if self._should_include_file(file_path):
474
- filtered.append(file_path)
475
- return filtered
476
-
477
- def _determine_category(self, file_path: Path) -> str:
478
- """사용자 정의 로직을 사용하여 파일 카테고리 결정."""
479
- # 사용자 정의 분류 로직
480
- ext = file_path.suffix.lower()
481
- if ext in ['.jpg', '.png', '.gif']:
482
- return 'images'
483
- elif ext in ['.pdf', '.doc', '.docx']:
484
- return 'documents'
485
- else:
486
- return 'other'
487
- ```
488
-
489
- #### 사용자 정의 업로드 전략
490
-
491
- ```python
492
- from synapse_sdk.plugins.categories.upload.actions.upload.strategies.upload.base import BaseUploadStrategy
493
- from typing import List, Dict, Any
494
-
495
- class CustomUploadStrategy(BaseUploadStrategy):
496
- """고급 재시도 로직을 포함한 사용자 정의 업로드 전략."""
497
-
498
- def upload_files(self, files: List[Dict[str, Any]], context: UploadContext) -> List[Dict[str, Any]]:
499
- """사용자 정의 배치 및 재시도 로직으로 파일 업로드."""
500
- uploaded_files = []
501
- batch_size = context.get_param('upload_batch_size', 10)
502
-
503
- # 사용자 정의 배치로 처리
504
- for i in range(0, len(files), batch_size):
505
- batch = files[i:i + batch_size]
506
- batch_results = self.upload_batch(batch, context)
507
- uploaded_files.extend(batch_results)
508
-
509
- return uploaded_files
510
-
511
- def upload_batch(self, batch: List[Dict[str, Any]], context: UploadContext) -> List[Dict[str, Any]]:
512
- """재시도 로직으로 파일 배치 업로드."""
513
- results = []
514
-
515
- for file_info in batch:
516
- max_retries = 3
517
- for attempt in range(max_retries):
518
- try:
519
- result = self._upload_single_file(file_info, context)
520
- results.append(result)
521
- break
522
- except Exception as e:
523
- if attempt == max_retries - 1:
524
- # 최종 시도 실패
525
- context.add_error(f"Failed to upload {file_info['file_path']}: {e}")
526
- else:
527
- # 재시도 전 대기
528
- time.sleep(2 ** attempt)
529
-
530
- return results
531
-
532
- def _upload_single_file(self, file_info: Dict[str, Any], context: UploadContext) -> Dict[str, Any]:
533
- """사용자 정의 로직으로 단일 파일 업로드."""
534
- # 사용자 정의 업로드 구현
535
- file_path = file_info['file_path']
536
-
537
- # 컨텍스트에서 스토리지 사용
538
- storage = context.storage
539
-
540
- # 여기에 사용자 정의 업로드 로직
541
- uploaded_file = {
542
- 'file_path': str(file_path),
543
- 'storage_path': f"uploads/{file_path.name}",
544
- 'size': file_path.stat().st_size,
545
- 'checksum': self._calculate_checksum(file_path)
546
- }
547
-
548
- return uploaded_file
549
- ```
550
-
551
- ### 사용자 정의 워크플로우 단계 생성
552
-
553
- 사용자 정의 워크플로우 단계는 기본 단계 클래스를 확장하고 필수 인터페이스를 구현합니다.
554
-
555
- #### 사용자 정의 처리 단계
556
-
557
- ```python
558
- from synapse_sdk.plugins.categories.upload.actions.upload.steps.base import BaseStep
559
- from synapse_sdk.plugins.categories.upload.actions.upload.context import UploadContext, StepResult
560
- from pathlib import Path
561
-
562
- class CustomProcessingStep(BaseStep):
563
- """특수 파일 처리를 위한 사용자 정의 처리 단계."""
564
-
565
- @property
566
- def name(self) -> str:
567
- return 'custom_processing'
568
-
569
- @property
570
- def progress_weight(self) -> float:
571
- return 0.15 # 전체 워크플로우의 15%
572
-
573
- def execute(self, context: UploadContext) -> StepResult:
574
- """사용자 정의 처리 로직 실행."""
575
- try:
576
- # 사용자 정의 처리 로직
577
- processed_files = self._process_files(context)
578
-
579
- # 결과로 컨텍스트 업데이트
580
- return self.create_success_result({
581
- 'processed_files': processed_files,
582
- 'processing_stats': self._get_processing_stats()
583
- })
584
-
585
- except Exception as e:
586
- return self.create_error_result(f'Custom processing failed: {str(e)}')
587
-
588
- def can_skip(self, context: UploadContext) -> bool:
589
- """단계를 건너뛸 수 있는지 결정."""
590
- # 처리할 파일이 없으면 건너뛰기
591
- return len(context.organized_files) == 0
592
-
593
- def rollback(self, context: UploadContext) -> None:
594
- """사용자 정의 처리 작업 롤백."""
595
- # 처리 중에 생성된 리소스 정리
596
- self._cleanup_processing_resources(context)
597
-
598
- def _process_files(self, context: UploadContext) -> List[Dict]:
599
- """사용자 정의 파일 처리 구현."""
600
- processed = []
601
-
602
- for file_info in context.organized_files:
603
- # 사용자 정의 처리 로직
604
- result = self._process_single_file(file_info)
605
- processed.append(result)
606
-
607
- return processed
608
-
609
- def _process_single_file(self, file_info: Dict) -> Dict:
610
- """단일 파일 처리."""
611
- # 사용자 정의 처리 구현
612
- return {
613
- 'original': file_info,
614
- 'processed': True,
615
- 'timestamp': datetime.now()
616
- }
617
- ```
618
-
619
- ### 전략 팩토리 확장
620
-
621
- 사용자 정의 전략을 사용 가능하게 하려면 StrategyFactory를 확장하세요:
622
-
623
- ```python
624
- from synapse_sdk.plugins.categories.upload.actions.upload.factory import StrategyFactory
625
-
626
- class CustomStrategyFactory(StrategyFactory):
627
- """사용자 정의 전략을 포함한 확장 팩토리."""
628
-
629
- def create_validation_strategy(self, params: Dict, context=None):
630
- """사용자 정의 옵션으로 검증 전략 생성."""
631
- validation_type = params.get('custom_validation_type', 'default')
632
-
633
- if validation_type == 'strict':
634
- return CustomValidationStrategy()
635
- else:
636
- return super().create_validation_strategy(params, context)
637
-
638
- def create_file_discovery_strategy(self, params: Dict, context=None):
639
- """사용자 정의 옵션으로 파일 발견 전략 생성."""
640
- discovery_mode = params.get('discovery_mode', 'default')
641
-
642
- if discovery_mode == 'advanced':
643
- return CustomFileDiscoveryStrategy()
644
- else:
645
- return super().create_file_discovery_strategy(params, context)
646
- ```
647
-
648
- ### 사용자 정의 업로드 액션
649
-
650
- 포괄적인 커스터마이제이션을 위해서는 UploadAction 자체를 확장하세요:
651
-
652
- ```python
653
- from synapse_sdk.plugins.categories.upload.actions.upload.action import UploadAction
654
- from synapse_sdk.plugins.categories.decorators import register_action
655
-
656
- @register_action
657
- class CustomUploadAction(UploadAction):
658
- """확장 워크플로우를 포함한 사용자 정의 업로드 액션."""
659
-
660
- name = 'custom_upload'
661
-
662
- def __init__(self, *args, **kwargs):
663
- super().__init__(*args, **kwargs)
664
- # 사용자 정의 전략 팩토리 사용
665
- self.strategy_factory = CustomStrategyFactory()
666
-
667
- def _configure_workflow(self) -> None:
668
- """추가 단계로 사용자 정의 워크플로우 구성."""
669
- # 표준 단계 등록
670
- super()._configure_workflow()
671
-
672
- # 사용자 정의 처리 단계 추가
673
- self.step_registry.register(CustomProcessingStep())
674
-
675
- def _configure_strategies(self, context=None) -> Dict[str, Any]:
676
- """사용자 정의 매개변수로 전략 구성."""
677
- strategies = super()._configure_strategies(context)
678
-
679
- # 사용자 정의 전략 추가
680
- strategies['custom_processing'] = self._create_custom_processing_strategy()
681
-
682
- return strategies
683
-
684
- def _create_custom_processing_strategy(self):
685
- """사용자 정의 처리 전략 생성."""
686
- return CustomProcessingStrategy(self.params)
687
- ```
688
-
689
- ### 사용자 정의 컴포넌트 테스트
690
-
691
- #### 사용자 정의 전략 테스트
692
-
693
- ```python
694
- import pytest
695
- from unittest.mock import Mock
696
- from pathlib import Path
697
-
698
- class TestCustomValidationStrategy:
699
-
700
- def setup_method(self):
701
- self.strategy = CustomValidationStrategy()
702
- self.context = Mock()
703
-
704
- def test_validate_files_success(self):
705
- """성공적인 파일 검증 테스트."""
706
- files = [Path('/test/file1.txt'), Path('/test/file2.jpg')]
707
- result = self.strategy.validate_files(files, self.context)
708
- assert result is True
709
-
710
- def test_validate_files_security_failure(self):
711
- """보안상 이유로 검증 실패 테스트."""
712
- files = [Path('/test/malware.exe')]
713
- result = self.strategy.validate_files(files, self.context)
714
- assert result is False
715
-
716
- def test_validate_large_file_failure(self):
717
- """큰 파일에 대한 검증 실패 테스트."""
718
- # 큰 크기를 반환하도록 파일 stat 모킹
719
- large_file = Mock(spec=Path)
720
- large_file.suffix = '.txt'
721
- large_file.stat.return_value.st_size = 200 * 1024 * 1024 # 200MB
722
-
723
- result = self.strategy.validate_security(large_file)
724
- assert result is False
725
- ```
726
-
727
- #### 사용자 정의 단계 테스트
728
-
729
- ```python
730
- class TestCustomProcessingStep:
731
-
732
- def setup_method(self):
733
- self.step = CustomProcessingStep()
734
- self.context = Mock()
735
- self.context.organized_files = [
736
- {'file_path': '/test/file1.txt'},
737
- {'file_path': '/test/file2.jpg'}
738
- ]
739
-
740
- def test_execute_success(self):
741
- """성공적인 단계 실행 테스트."""
742
- result = self.step.execute(self.context)
743
-
744
- assert result.success is True
745
- assert 'processed_files' in result.data
746
- assert len(result.data['processed_files']) == 2
747
-
748
- def test_can_skip_with_no_files(self):
749
- """단계 건너뛰기 로직 테스트."""
750
- self.context.organized_files = []
751
- assert self.step.can_skip(self.context) is True
752
-
753
- def test_rollback_cleanup(self):
754
- """롤백 정리 테스트."""
755
- # 이것은 예외를 발생시키지 않아야 함
756
- self.step.rollback(self.context)
757
- ```
758
-
759
- ## 업로드 매개변수
760
-
761
- 업로드 액션은 포괄적인 매개변수 검증을 위해 `UploadParams`를 사용합니다:
762
-
763
- ### 필수 매개변수
764
-
765
- | 매개변수 | 타입 | 설명 | 검증 |
766
- | ----------------- | ----- | ----------------------- | ---------------------- |
767
- | `name` | `str` | 읽기 쉬운 업로드 이름 | 빈 값이 아니어야 함 |
768
- | `path` | `str` | 소스 파일/디렉토리 경로 | 유효한 경로여야 함 |
769
- | `storage` | `int` | 대상 스토리지 ID | API를 통해 존재해야 함 |
770
- | `data_collection` | `int` | 데이터 컬렉션 ID | API를 통해 존재해야 함 |
771
-
772
- ### 선택적 매개변수
773
-
774
- | 매개변수 | 타입 | 기본값 | 설명 |
775
- | ------------------------------- | ------------- | ------- | --------------------------- |
776
- | `description` | `str \| None` | `None` | 업로드 설명 |
777
- | `project` | `int \| None` | `None` | 프로젝트 ID (제공시 검증됨) |
778
- | `excel_metadata_path` | `str \| None` | `None` | Excel 메타데이터 파일 경로 |
779
- | `is_recursive` | `bool` | `False` | 디렉토리를 재귀적으로 스캔 |
780
- | `max_file_size_mb` | `int` | `50` | 최대 파일 크기 (MB) |
781
- | `creating_data_unit_batch_size` | `int` | `100` | 데이터 단위 배치 크기 |
782
- | `use_async_upload` | `bool` | `True` | 비동기 처리 사용 |
783
-
784
- ### 매개변수 검증
785
-
786
- 시스템은 실시간 검증을 수행합니다:
787
-
788
- ```python
789
- # 스토리지 검증
790
- @field_validator('storage', mode='before')
791
- @classmethod
792
- def check_storage_exists(cls, value: str, info) -> str:
793
- action = info.context['action']
794
- client = action.client
795
- try:
796
- client.get_storage(value)
797
- except ClientError:
798
- raise PydanticCustomError('client_error', 'Storage not found')
799
- return value
800
- ```
801
-
802
- **검증 규칙:**
803
-
804
- - `source_path`: 읽기 가능한 디렉터리 또는 파일이어야 함
805
- - 모든 ID 필드: 비어있지 않은 문자열이어야 함
806
- - `batch_size`: 1 이상의 정수
807
- - `max_workers`: 1 이상의 정수
808
- - `include_patterns`/`exclude_patterns`: 유효한 glob 패턴 목록
809
-
810
- ### UploadRun
811
-
812
- 업로드 실행과 로깅을 관리합니다.
813
-
814
- ```python
815
- class UploadRun(BaseRun):
816
- def __init__(self, action_name: str = "upload"):
817
- """업로드 실행을 초기화합니다."""
818
-
819
- def log_message_with_code(self, log_code: LogCode, **kwargs):
820
- """로그 코드를 사용하여 메시지를 로깅합니다."""
821
-
822
- def log_upload_event(self, event_type: str, details: Dict):
823
- """업로드 이벤트를 로깅합니다."""
824
- ```
825
-
826
- ### 열거형
827
-
828
- #### LogCode
829
-
830
- 업로드 작업에 대한 타입 안전 로깅 코드:
831
-
832
- ```python
833
- class LogCode(Enum):
834
- UPLOAD_STARTED = "UPLOAD_001"
835
- FILE_DISCOVERED = "UPLOAD_002"
836
- FILE_PROCESSED = "UPLOAD_003"
837
- BATCH_COMPLETED = "UPLOAD_004"
838
- UPLOAD_COMPLETED = "UPLOAD_005"
839
- UPLOAD_FAILED = "UPLOAD_006"
840
- # ... 총 36개 코드
841
- ```
842
-
843
- #### UploadStatus
844
-
845
- 업로드 작업 상태:
846
-
847
- ```python
848
- class UploadStatus(Enum):
849
- SUCCESS = "success"
850
- FAILED = "failed"
851
- ```
852
-
853
- ### 유틸리티 클래스
854
-
855
- #### ExcelSecurityConfig
856
-
857
- Excel 파일 보안 설정:
858
-
859
- ```python
860
- class ExcelSecurityConfig:
861
- max_file_size_mb: int = 10 # 파일 크기 제한 (MB)
862
- max_rows: int = 100000 # 행 수 제한
863
- max_columns: int = 50 # 열 수 제한
864
-
865
- @classmethod
866
- def from_action_config(cls, action_config) -> 'ExcelSecurityConfig':
867
- """config.yaml에서 설정을 로드합니다."""
868
- ```
869
-
870
- #### PathAwareJSONEncoder
871
-
872
- Path 및 datetime 객체를 위한 사용자 정의 JSON 인코더:
873
-
874
- ```python
875
- class PathAwareJSONEncoder:
876
- """JSON 직렬화를 위한 사용자 정의 인코더"""
877
-
878
- @staticmethod
879
- def default(obj):
880
- """지원되는 타입을 JSON 호환 형식으로 변환"""
881
- if isinstance(obj, Path):
882
- return str(obj)
883
- elif isinstance(obj, datetime):
884
- return obj.isoformat()
885
- return json.JSONEncoder.default(obj)
886
- ```
887
-
888
- **지원 타입:**
889
-
890
- - Path 객체 (문자열로 변환)
891
- - Datetime 객체 (ISO 형식)
892
- - 표준 JSON 직렬화 가능 타입
893
-
894
- ## Excel 메타데이터 처리
895
-
896
- 업로드 플러그인은 포괄적인 파일명 매칭, 유연한 헤더 지원 및 최적화된 성능을 통한 고급 Excel 메타데이터 처리를 제공합니다:
897
-
898
- ### Excel 파일 형식
899
-
900
- Excel 파일은 유연한 헤더 형식과 포괄적인 파일명 매칭을 지원합니다:
901
-
902
- #### 지원되는 헤더 형식
903
-
904
- 대소문자를 구분하지 않는 매칭으로 두 헤더 형식 모두 지원됩니다:
905
-
906
- **옵션 1: "filename" 헤더**
907
- | filename | category | description | custom_field |
908
- | ---------- | -------- | ------------------ | ------------ |
909
- | image1.jpg | nature | Mountain landscape | high_res |
910
- | image2.png | urban | City skyline | processed |
911
-
912
- **옵션 2: "file_name" 헤더**
913
- | file_name | category | description | custom_field |
914
- | ---------- | -------- | ------------------ | ------------ |
915
- | image1.jpg | nature | Mountain landscape | high_res |
916
- | image2.png | urban | City skyline | processed |
917
-
918
- #### 파일명 매칭 전략
919
-
920
- 시스템은 파일과 메타데이터를 연결하기 위해 포괄적인 5단계 우선순위 매칭 알고리즘을 사용합니다:
921
-
922
- 1. **정확한 stem 매칭** (최우선): `image1`이 `image1.jpg`와 매칭
923
- 2. **정확한 파일명 매칭**: `image1.jpg`가 `image1.jpg`와 매칭
924
- 3. **메타데이터 키 stem 매칭**: `path/image1.ext` stem이 `image1`과 매칭
925
- 4. **부분 경로 매칭**: `/uploads/image1.jpg`에 `image1` 포함
926
- 5. **전체 경로 매칭**: 복잡한 구조에 대한 완전한 경로 매칭
927
-
928
- 이 강력한 매칭은 파일 구성이나 명명 규칙에 관계없이 메타데이터가 올바르게 연결되도록 보장합니다.
929
-
930
- ### 보안 검증
931
-
932
- Excel 파일은 포괄적인 보안 검증을 받습니다:
933
-
934
- ```python
935
- class ExcelSecurityConfig:
936
- max_file_size_mb: int = 10 # 파일 크기 제한 (MB)
937
- max_rows: int = 100000 # 행 수 제한
938
- max_columns: int = 50 # 열 수 제한
939
- ```
940
-
941
- #### 고급 보안 기능
942
-
943
- - **파일 형식 검증**: Excel 파일 시그니처 확인 (.xlsx의 경우 PK, .xls의 경우 복합 문서)
944
- - **메모리 추정**: 대용량 스프레드시트로 인한 메모리 고갈 방지
945
- - **내용 정화**: 지나치게 긴 값의 자동 잘라내기
946
- - **오류 복원력**: 손상되거나 접근할 수 없는 파일의 우아한 처리
947
-
948
- ### config.yaml을 통한 구성
949
-
950
- 보안 제한 및 처리 옵션을 구성할 수 있습니다:
951
-
952
- ```yaml
953
- actions:
954
- upload:
955
- excel_config:
956
- max_file_size_mb: 10 # Excel 파일 최대 크기 (MB)
957
- max_rows: 100000 # 허용되는 최대 행 수
958
- max_columns: 50 # 허용되는 최대 열 수
959
- ```
960
-
961
- ### 성능 최적화
962
-
963
- Excel 메타데이터 처리에는 여러 성능 향상 기능이 포함되어 있습니다:
964
-
965
- #### 메타데이터 인덱싱
966
-
967
- - **O(1) 해시 검색**: 정확한 stem 및 파일명 매칭용
968
- - **사전 구축된 인덱스**: 일반적인 매칭 패턴용
969
- - **대체 알고리즘**: 복잡한 경로 매칭 시나리오용
970
-
971
- #### 효율적인 처리
972
-
973
- - **최적화된 행 처리**: 빈 행을 조기에 건너뛰기
974
- - **메모리 인식 작업**: 배치로 파일 처리
975
- - **스마트 파일 발견**: 반복되는 변환을 피하기 위한 경로 문자열 캐시
976
-
977
- ### 메타데이터 처리 플로우
978
-
979
- 1. **보안 검증**: 파일 크기, 형식 및 내용 제한
980
- 2. **헤더 검증**: 대소문자를 구분하지 않는 매칭으로 "filename" 및 "file_name" 모두 지원
981
- 3. **인덱스 구축**: 성능을 위한 O(1) 검색 구조 생성
982
- 4. **내용 처리**: 최적화를 통한 행별 메타데이터 추출
983
- 5. **데이터 정화**: 자동 잘라내기 및 검증
984
- 6. **패턴 매칭**: 5단계 파일명 연결 알고리즘
985
- 7. **매핑 생성**: 최적화된 파일명에서 메타데이터로의 매핑
986
-
987
- ### Excel 메타데이터 매개변수
988
-
989
- 사용자 정의 Excel 메타데이터 파일 경로를 지정할 수 있습니다:
990
-
991
- ```python
992
- params = {
993
- "name": "Excel 메타데이터 업로드",
994
- "path": "/data/files",
995
- "storage": 1,
996
- "data_collection": 5,
997
- "excel_metadata_path": "/data/custom_metadata.xlsx" # 사용자 정의 Excel 파일
998
- }
999
- ```
1000
-
1001
- #### 경로 해결
1002
-
1003
- - **절대 경로**: 존재하고 접근 가능한 경우 직접 사용
1004
- - **상대 경로**: 업로드 경로에 상대적으로 해결
1005
- - **기본 발견**: 경로가 지정되지 않은 경우 자동으로 `meta.xlsx` 또는 `meta.xls` 검색
1006
- - **스토리지 통합**: 적절한 경로 해결을 위해 스토리지 구성 사용
1007
-
1008
- ### 오류 처리
1009
-
1010
- 포괄적인 오류 처리로 강력한 작업을 보장합니다:
1011
-
1012
- ```python
1013
- # Excel 처리 오류는 우아하게 처리됩니다
1014
- try:
1015
- metadata = process_excel_metadata(excel_path)
1016
- except ExcelSecurityError as e:
1017
- # 보안 위반 - 파일이 너무 크거나 행이 너무 많음 등
1018
- log_security_violation(e)
1019
- except ExcelParsingError as e:
1020
- # 파싱 실패 - 손상된 파일, 잘못된 형식 등
1021
- log_parsing_error(e)
1022
- ```
1023
-
1024
- #### 오류 복구
1025
-
1026
- - **우아한 성능 저하**: Excel이 실패하면 빈 메타데이터로 처리 계속
1027
- - **상세 로깅**: 다양한 실패 유형에 대한 특정 오류 코드
1028
- - **경로 검증**: 매개변수 처리 중 포괄적인 검증
1029
- - **대체 동작**: 메타데이터를 처리할 수 없을 때 스마트 기본값
1030
-
1031
- ## 파일 구성
1032
-
1033
- 업로드 시스템은 파일을 타입에 따라 자동으로 구성합니다:
1034
-
1035
- ### 타입 감지
1036
-
1037
- 파일은 다음을 기반으로 분류됩니다:
1038
-
1039
- - 파일 확장자 패턴
1040
- - MIME 타입 감지
1041
- - 내용 분석
1042
- - 사용자 정의 타입 규칙
1043
-
1044
- ### 디렉토리 구조
1045
-
1046
- ```
1047
- upload_output/
1048
- ├── images/
1049
- │ ├── image1.jpg
1050
- │ └── image2.png
1051
- ├── documents/
1052
- │ ├── report.pdf
1053
- │ └── data.xlsx
1054
- └── videos/
1055
- └── presentation.mp4
1056
- ```
1057
-
1058
- ### 배치 처리
1059
-
1060
- 파일은 구성 가능한 배치로 처리됩니다:
1061
-
1062
- ```python
1063
- # 배치 크기 구성
1064
- params = {
1065
- "creating_data_unit_batch_size": 100,
1066
- "use_async_upload": True
1067
- }
1068
- ```
1069
-
1070
- ## 진행률 추적 및 메트릭
1071
-
1072
- ### 진행률 카테고리
1073
-
1074
- 업로드 액션은 세 가지 주요 단계에서 진행률을 추적합니다:
1075
-
1076
- | 카테고리 | 비율 | 설명 |
1077
- | --------------------- | ---- | ------------------------ |
1078
- | `analyze_collection` | 2% | 매개변수 검증 및 설정 |
1079
- | `upload_data_files` | 38% | 파일 업로드 처리 |
1080
- | `generate_data_units` | 60% | 데이터 단위 생성 및 완료 |
1081
-
1082
- ### 메트릭 수집
1083
-
1084
- 모니터링을 위해 실시간 메트릭이 수집됩니다:
1085
-
1086
- ```python
1087
- metrics_categories = {
1088
- 'data_files': {
1089
- 'stand_by': 0, # 처리 대기 중인 파일
1090
- 'failed': 0, # 업로드 실패한 파일
1091
- 'success': 0, # 성공적으로 업로드된 파일
1092
- },
1093
- 'data_units': {
1094
- 'stand_by': 0, # 생성 대기 중인 단위
1095
- 'failed': 0, # 생성 실패한 단위
1096
- 'success': 0, # 성공적으로 생성된 단위
1097
- },
1098
- }
1099
- ```
1100
-
1101
- ## 타입 안전 로깅
1102
-
1103
- 업로드 시스템은 일관성을 위해 열거형 기반 로깅을 사용합니다:
1104
-
1105
- ### 로그 코드
1106
-
1107
- ```python
1108
- class LogCode(str, Enum):
1109
- VALIDATION_FAILED = 'VALIDATION_FAILED'
1110
- NO_FILES_FOUND = 'NO_FILES_FOUND'
1111
- EXCEL_SECURITY_VIOLATION = 'EXCEL_SECURITY_VIOLATION'
1112
- EXCEL_PARSING_ERROR = 'EXCEL_PARSING_ERROR'
1113
- FILES_DISCOVERED = 'FILES_DISCOVERED'
1114
- UPLOADING_DATA_FILES = 'UPLOADING_DATA_FILES'
1115
- GENERATING_DATA_UNITS = 'GENERATING_DATA_UNITS'
1116
- IMPORT_COMPLETED = 'IMPORT_COMPLETED'
1117
- ```
1118
-
1119
- ### 로깅 사용법
1120
-
1121
- ```python
1122
- # 기본 로깅
1123
- run.log_message_with_code(LogCode.FILES_DISCOVERED, file_count)
1124
-
1125
- # 사용자 정의 레벨로
1126
- run.log_message_with_code(
1127
- LogCode.EXCEL_SECURITY_VIOLATION,
1128
- filename,
1129
- level=Context.DANGER
1130
- )
1131
-
1132
- # 업로드 특정 이벤트
1133
- run.log_upload_event(LogCode.UPLOADING_DATA_FILES, batch_size)
1134
- ```
1135
-
1136
- ## 마이그레이션 가이드
1137
-
1138
- ### 레거시에서 리팩토링된 아키텍처로
1139
-
1140
- 업로드 액션은 **100% 하위 호환성**을 유지하면서 현대적인 디자인 패턴을 사용하여 리팩토링되었습니다. 기존 코드는 변경 없이 계속 작동합니다.
1141
-
1142
- #### 주요 변경 사항
1143
-
1144
- **이전 (레거시 모놀리식):**
1145
-
1146
- - 모든 로직을 포함한 단일 900+ 줄 액션 클래스
1147
- - 검증, 파일 발견 등에 대한 하드코딩된 동작
1148
- - 확장성이나 커스터마이제이션 옵션 없음
1149
- - 전반에 걸친 수동 오류 처리
1150
-
1151
- **이후 (전략/파사드 패턴):**
1152
-
1153
- - 8개 워크플로우 단계로 명확한 관심사 분리
1154
- - 다양한 동작을 위한 플러그형 전략
1155
- - 사용자 정의 구현을 위한 확장 가능한 아키텍처
1156
- - 자동 롤백 및 포괄적인 오류 처리
1157
-
1158
- #### 하위 호환성
1159
-
1160
- ```python
1161
- # 이 레거시 사용법은 동일하게 작동합니다
1162
- from synapse_sdk.plugins.categories.upload.actions.upload.action import UploadAction
1163
-
1164
- params = {
1165
- "name": "My Upload",
1166
- "path": "/data/files",
1167
- "storage": 1,
1168
- "data_collection": 5 # 'collection'에서 'data_collection'으로 변경
1169
- }
1170
-
1171
- action = UploadAction(params=params, plugin_config=config)
1172
- result = action.start() # 이전과 동일하게 작동
1173
- ```
1174
-
1175
- #### 향상된 기능
1176
-
1177
- 리팩토링된 아키텍처는 새로운 기능을 제공합니다:
1178
-
1179
- ```python
1180
- # 자세한 워크플로우 정보 가져오기
1181
- action = UploadAction(params=params, plugin_config=config)
1182
- workflow_info = action.get_workflow_summary()
1183
- print(f"Configured with {workflow_info['step_count']} steps")
1184
- print(f"Available strategies: {workflow_info['available_strategies']}")
1185
-
1186
- # 실행하고 자세한 결과 가져오기
1187
- result = action.start()
1188
- print(f"Success: {result['success']}")
1189
- print(f"Uploaded files: {result['uploaded_files_count']}")
1190
- print(f"Generated data units: {result['generated_data_units_count']}")
1191
- print(f"Errors: {result['errors']}")
1192
- print(f"Metrics: {result['metrics']}")
1193
- ```
1194
-
1195
- #### 매개변수 변경
1196
-
1197
- 하나의 매개변수 이름만 변경되었습니다:
1198
-
1199
- | 레거시 | 리팩토링 | 상태 |
1200
- | ------------------ | ----------------- | ------------- |
1201
- | `collection` | `data_collection` | **필수 변경** |
1202
- | 기타 모든 매개변수 | 변경 없음 | 완전 호환 |
1203
-
1204
- #### 마이그레이션의 이점
1205
-
1206
- - **더 나은 오류 처리**: 실패 시 자동 롤백
1207
- - **진행률 추적**: 워크플로우 단계 전반의 자세한 진행률 메트릭
1208
- - **확장성**: 사용자 정의 전략 및 단계 추가
1209
- - **테스트**: 모킹 친화적인 아키텍처로 더 나은 테스트 가능성
1210
- - **유지보수성**: 명확한 관심사 분리
1211
- - **성능**: 더 효율적인 리소스 관리
1212
-
1213
- ## 사용 예제
1214
-
1215
- ### 기본 파일 업로드 (리팩토링된 아키텍처)
1216
-
1217
- ```python
1218
- from synapse_sdk.plugins.categories.upload.actions.upload.action import UploadAction
1219
-
1220
- # 새 아키텍처로 기본 업로드 구성
1221
- params = {
1222
- "name": "Dataset Upload",
1223
- "description": "Training dataset for ML model",
1224
- "path": "/data/training_images",
1225
- "storage": 1,
1226
- "data_collection": 5, # 참고: 'collection' 대신 'data_collection'
1227
- "is_recursive": True,
1228
- "max_file_size_mb": 100
1229
- }
1230
-
1231
- action = UploadAction(
1232
- params=params,
1233
- plugin_config=plugin_config
1234
- )
1235
-
1236
- # 자동 단계 기반 워크플로우 및 롤백으로 실행
1237
- result = action.start()
1238
-
1239
- # 향상된 결과 정보
1240
- print(f"Upload successful: {result['success']}")
1241
- print(f"Uploaded {result['uploaded_files_count']} files")
1242
- print(f"Generated {result['generated_data_units_count']} data units")
1243
- print(f"Workflow errors: {result['errors']}")
1244
-
1245
- # 자세한 메트릭에 액세스
1246
- workflow_metrics = result['metrics'].get('workflow', {})
1247
- print(f"Total steps executed: {workflow_metrics.get('current_step', 0)}")
1248
- print(f"Progress completed: {workflow_metrics.get('progress_percentage', 0)}%")
1249
- ```
1250
-
1251
- ### 진행률 추적이 포함된 Excel 메타데이터 업로드
1252
-
1253
- ```python
1254
- # Excel 메타데이터 및 진행률 모니터링으로 업로드
1255
- params = {
1256
- "name": "Annotated Dataset Upload",
1257
- "path": "/data/images",
1258
- "storage": 1,
1259
- "data_collection": 5,
1260
- "excel_metadata_path": "/data/metadata.xlsx",
1261
- "is_recursive": False,
1262
- "creating_data_unit_batch_size": 50
1263
- }
1264
-
1265
- action = UploadAction(
1266
- params=params,
1267
- plugin_config=plugin_config
1268
- )
1269
-
1270
- # 실행 전 워크플로우 요약 가져오기
1271
- workflow_info = action.get_workflow_summary()
1272
- print(f"Workflow configured with {workflow_info['step_count']} steps")
1273
- print(f"Total progress weight: {workflow_info['total_progress_weight']}")
1274
- print(f"Steps: {workflow_info['steps']}")
1275
-
1276
- # 향상된 오류 처리로 실행
1277
- try:
1278
- result = action.start()
1279
- if result['success']:
1280
- print("Upload completed successfully!")
1281
- print(f"Files: {result['uploaded_files_count']}")
1282
- print(f"Data units: {result['generated_data_units_count']}")
1283
- else:
1284
- print("Upload failed with errors:")
1285
- for error in result['errors']:
1286
- print(f" - {error}")
1287
- except Exception as e:
1288
- print(f"Upload action failed: {e}")
1289
- ```
1290
-
1291
- ### 사용자 정의 전략 업로드
1292
-
1293
- ```python
1294
- from synapse_sdk.plugins.categories.upload.actions.upload.action import UploadAction
1295
- from my_custom_strategies import CustomValidationStrategy
1296
-
1297
- # 사용자 정의 팩토리로 액션 생성
1298
- class CustomUploadAction(UploadAction):
1299
- def _configure_strategies(self, context=None):
1300
- strategies = super()._configure_strategies(context)
1301
-
1302
- # 사용자 정의 검증으로 오버라이드
1303
- if self.params.get('use_strict_validation'):
1304
- strategies['validation'] = CustomValidationStrategy()
1305
-
1306
- return strategies
1307
-
1308
- # 사용자 정의 액션 사용
1309
- params = {
1310
- "name": "Strict Validation Upload",
1311
- "path": "/data/sensitive_files",
1312
- "storage": 1,
1313
- "data_collection": 5,
1314
- "use_strict_validation": True,
1315
- "max_file_size_mb": 10 # 더 엄격한 제한
1316
- }
1317
-
1318
- action = CustomUploadAction(
1319
- params=params,
1320
- plugin_config=plugin_config
1321
- )
1322
-
1323
- result = action.start()
1324
- ```
1325
-
1326
- ### 사용자 정의 구성을 포함한 배치 처리
1327
-
1328
- ```python
1329
- import os
1330
-
1331
- # Excel 처리 제한 구성
1332
- os.environ['EXCEL_MAX_FILE_SIZE_MB'] = '20'
1333
- os.environ['EXCEL_MAX_ROWS'] = '20000'
1334
-
1335
- # 사용자 정의 설정을 포함한 대량 배치 업로드
1336
- params = {
1337
- "name": "Large Batch Upload",
1338
- "path": "/data/large_dataset",
1339
- "storage": 2,
1340
- "data_collection": 10,
1341
- "is_recursive": True,
1342
- "max_file_size_mb": 500,
1343
- "creating_data_unit_batch_size": 200,
1344
- "use_async_upload": True
1345
- }
1346
-
1347
- action = UploadAction(
1348
- params=params,
1349
- plugin_config=plugin_config
1350
- )
1351
-
1352
- # 진행률 모니터링으로 실행
1353
- result = action.start()
1354
-
1355
- # 결과 분석
1356
- print(f"Batch upload summary:")
1357
- print(f" Success: {result['success']}")
1358
- print(f" Files processed: {result['uploaded_files_count']}")
1359
- print(f" Data units created: {result['generated_data_units_count']}")
1360
-
1361
- # 카테고리별 메트릭 확인
1362
- metrics = result['metrics']
1363
- if 'data_files' in metrics:
1364
- files_metrics = metrics['data_files']
1365
- print(f" Files - Success: {files_metrics.get('success', 0)}")
1366
- print(f" Files - Failed: {files_metrics.get('failed', 0)}")
1367
-
1368
- if 'data_units' in metrics:
1369
- units_metrics = metrics['data_units']
1370
- print(f" Units - Success: {units_metrics.get('success', 0)}")
1371
- print(f" Units - Failed: {units_metrics.get('failed', 0)}")
1372
- ```
1373
-
1374
- ### 오류 처리 및 롤백
1375
-
1376
- ```python
1377
- # 자동 롤백을 포함한 향상된 오류 처리 시연
1378
- params = {
1379
- "name": "Error Recovery Example",
1380
- "path": "/data/problematic_files",
1381
- "storage": 1,
1382
- "data_collection": 5,
1383
- "is_recursive": True
1384
- }
1385
-
1386
- action = UploadAction(
1387
- params=params,
1388
- plugin_config=plugin_config
1389
- )
1390
-
1391
- try:
1392
- result = action.start()
1393
-
1394
- if not result['success']:
1395
- print("Upload failed, but cleanup was automatic:")
1396
- print(f"Errors encountered: {len(result['errors'])}")
1397
- for i, error in enumerate(result['errors'], 1):
1398
- print(f" {i}. {error}")
1399
-
1400
- # 롤백이 수행되었는지 확인 (오케스트레이터 내부를 통해)
1401
- workflow_metrics = result['metrics'].get('workflow', {})
1402
- current_step = workflow_metrics.get('current_step', 0)
1403
- total_steps = workflow_metrics.get('total_steps', 0)
1404
- print(f"Workflow stopped at step {current_step} of {total_steps}")
1405
-
1406
- except Exception as e:
1407
- print(f"Critical upload failure: {e}")
1408
- # 예외 전파 전에 롤백이 자동으로 수행됨
1409
- ```
1410
-
1411
- ## 오류 처리
1412
-
1413
- ### 예외 타입
1414
-
1415
- 업로드 시스템은 특정 예외를 정의합니다:
1416
-
1417
- ```python
1418
- # 보안 위반
1419
- try:
1420
- action.start()
1421
- except ExcelSecurityError as e:
1422
- print(f"Excel security violation: {e}")
1423
-
1424
- # 파싱 오류
1425
- except ExcelParsingError as e:
1426
- print(f"Excel parsing failed: {e}")
1427
-
1428
- # 일반 업로드 오류
1429
- except ActionError as e:
1430
- print(f"Upload action failed: {e}")
1431
- ```
1432
-
1433
- ### 검증 오류
1434
-
1435
- 매개변수 검증은 자세한 오류 메시지를 제공합니다:
1436
-
1437
- ```python
1438
- from pydantic import ValidationError
1439
-
1440
- try:
1441
- params = UploadParams(**invalid_params)
1442
- except ValidationError as e:
1443
- for error in e.errors():
1444
- print(f"Field {error['loc']}: {error['msg']}")
1445
- ```
1446
-
1447
- ## API 레퍼런스
1448
-
1449
- ### 핵심 컴포넌트
1450
-
1451
- #### UploadAction
1452
-
1453
- 파일 처리 작업을 위한 전략 및 파사드 패턴을 구현하는 메인 업로드 액션 클래스입니다.
1454
-
1455
- **클래스 속성:**
1456
-
1457
- - `name = 'upload'` - 액션 식별자
1458
- - `category = PluginCategory.UPLOAD` - 플러그인 카테고리
1459
- - `method = RunMethod.JOB` - 실행 방법
1460
- - `run_class = UploadRun` - 전문 실행 관리
1461
- - `params_model = UploadParams` - 매개변수 검증 모델
1462
- - `strategy_factory: StrategyFactory` - 전략 구현 생성
1463
- - `step_registry: StepRegistry` - 워크플로우 단계 관리
1464
-
1465
- **주요 메서드:**
1466
-
1467
- - `start() -> Dict[str, Any]` - 오케스트레이션된 업로드 워크플로우 실행
1468
- - `get_workflow_summary() -> Dict[str, Any]` - 구성된 워크플로우 요약 가져오기
1469
- - `_configure_workflow() -> None` - 실행 순서로 워크플로우 단계 등록
1470
- - `_configure_strategies(context=None) -> Dict[str, Any]` - 전략 인스턴스 생성
1471
-
1472
- **진행률 카테고리:**
1473
-
1474
- ```python
1475
- progress_categories = {
1476
- 'analyze_collection': {'proportion': 2},
1477
- 'upload_data_files': {'proportion': 38},
1478
- 'generate_data_units': {'proportion': 60},
1479
- }
1480
- ```
1481
-
1482
- #### UploadOrchestrator
1483
-
1484
- 자동 롤백을 포함한 완전한 업로드 워크플로우를 조정하는 파사드 컴포넌트입니다.
1485
-
1486
- **클래스 속성:**
1487
-
1488
- - `context: UploadContext` - 워크플로우 전반의 공유 상태
1489
- - `step_registry: StepRegistry` - 워크플로우 단계 레지스트리
1490
- - `strategies: Dict[str, Any]` - 전략 구현
1491
- - `executed_steps: List[BaseStep]` - 성공적으로 실행된 단계
1492
- - `current_step_index: int` - 워크플로우의 현재 위치
1493
- - `rollback_executed: bool` - 롤백이 수행되었는지 여부
1494
-
1495
- **주요 메서드:**
1496
-
1497
- - `execute() -> Dict[str, Any]` - 오류 처리를 포함한 완전한 워크플로우 실행
1498
- - `get_workflow_summary() -> Dict[str, Any]` - 실행 요약 및 메트릭 가져오기
1499
- - `get_executed_steps() -> List[BaseStep]` - 성공적으로 실행된 단계 목록 가져오기
1500
- - `is_rollback_executed() -> bool` - 롤백이 수행되었는지 확인
1501
- - `_execute_step(step: BaseStep) -> StepResult` - 개별 워크플로우 단계 실행
1502
- - `_handle_step_failure(step: BaseStep, error: Exception) -> None` - 단계 실패 처리
1503
- - `_rollback_executed_steps() -> None` - 실행된 단계를 역순으로 롤백
1504
-
1505
- #### UploadContext
1506
-
1507
- 워크플로우 컴포넌트 간의 공유 상태 및 통신을 유지하는 컨텍스트 객체입니다.
1508
-
1509
- **상태 속성:**
1510
-
1511
- - `params: Dict` - 업로드 매개변수
1512
- - `run: UploadRun` - 실행 관리 인스턴스
1513
- - `client: Any` - 외부 작업을 위한 API 클라이언트
1514
- - `storage: Any` - 스토리지 구성 객체
1515
- - `pathlib_cwd: Path` - 현재 작업 디렉토리 경로
1516
- - `metadata: Dict[str, Dict[str, Any]]` - 파일 메타데이터 매핑
1517
- - `file_specifications: Dict[str, Any]` - 데이터 컬렉션 파일 사양
1518
- - `organized_files: List[Dict[str, Any]]` - 구성된 파일 정보
1519
- - `uploaded_files: List[Dict[str, Any]]` - 성공적으로 업로드된 파일
1520
- - `data_units: List[Dict[str, Any]]` - 생성된 데이터 단위
1521
-
1522
- **진행률 및 메트릭:**
1523
-
1524
- - `metrics: Dict[str, Any]` - 워크플로우 메트릭 및 통계
1525
- - `errors: List[str]` - 축적된 오류 메시지
1526
- - `step_results: List[StepResult]` - 실행된 단계의 결과
1527
-
1528
- **전략 및 롤백:**
1529
-
1530
- - `strategies: Dict[str, Any]` - 주입된 전략 구현
1531
- - `rollback_data: Dict[str, Any]` - 롤백 작업을 위한 데이터
1532
-
1533
- **주요 메서드:**
1534
-
1535
- - `update(result: StepResult) -> None` - 단계 결과로 컨텍스트 업데이트
1536
- - `get_result() -> Dict[str, Any]` - 최종 결과 딕셔너리 생성
1537
- - `has_errors() -> bool` - 축적된 오류 확인
1538
- - `get_last_step_result() -> Optional[StepResult]` - 가장 최근 단계 결과 가져오기
1539
- - `update_metrics(category: str, metrics: Dict[str, Any]) -> None` - 메트릭 업데이트
1540
- - `add_error(error: str) -> None` - 컨텍스트에 오류 추가
1541
- - `get_param(key: str, default: Any = None) -> Any` - 기본값이 있는 매개변수 가져오기
1542
-
1543
- #### StepRegistry
1544
-
1545
- 워크플로우 단계의 컬렉션 및 실행 순서를 관리하는 레지스트리입니다.
1546
-
1547
- **속성:**
1548
-
1549
- - `_steps: List[BaseStep]` - 실행 순서로 등록된 워크플로우 단계
1550
-
1551
- **주요 메서드:**
1552
-
1553
- - `register(step: BaseStep) -> None` - 워크플로우 단계 등록
1554
- - `get_steps() -> List[BaseStep]` - 순서대로 모든 등록된 단계 가져오기
1555
- - `get_total_progress_weight() -> float` - 총 진행률 가중치 계산
1556
- - `clear() -> None` - 모든 등록된 단계 지우기
1557
- - `__len__() -> int` - 등록된 단계 수 가져오기
1558
-
1559
- #### StrategyFactory
1560
-
1561
- 매개변수를 기반으로 적절한 전략 구현을 생성하는 팩토리 컴포넌트입니다.
1562
-
1563
- **주요 메서드:**
1564
-
1565
- - `create_validation_strategy(params: Dict, context=None) -> BaseValidationStrategy` - 검증 전략 생성
1566
- - `create_file_discovery_strategy(params: Dict, context=None) -> BaseFileDiscoveryStrategy` - 파일 발견 전략 생성
1567
- - `create_metadata_strategy(params: Dict, context=None) -> BaseMetadataStrategy` - 메타데이터 처리 전략 생성
1568
- - `create_upload_strategy(params: Dict, context: UploadContext) -> BaseUploadStrategy` - 업로드 전략 생성 (컨텍스트 필요)
1569
- - `create_data_unit_strategy(params: Dict, context: UploadContext) -> BaseDataUnitStrategy` - 데이터 단위 전략 생성 (컨텍스트 필요)
1570
- - `get_available_strategies() -> Dict[str, List[str]]` - 사용 가능한 전략 타입 및 구현 가져오기
1571
-
1572
- ### 워크플로우 단계
1573
-
1574
- #### BaseStep (추상)
1575
-
1576
- 공통 인터페이스 및 유틸리티를 제공하는 모든 워크플로우 단계의 기본 클래스입니다.
1577
-
1578
- **추상 속성:**
1579
-
1580
- - `name: str` - 고유한 단계 식별자
1581
- - `progress_weight: float` - 진행률 계산을 위한 가중치 (합은 1.0이어야 함)
1582
-
1583
- **추상 메서드:**
1584
-
1585
- - `execute(context: UploadContext) -> StepResult` - 단계 로직 실행
1586
- - `can_skip(context: UploadContext) -> bool` - 단계를 건너뛸 수 있는지 결정
1587
- - `rollback(context: UploadContext) -> None` - 단계 작업 롤백
1588
-
1589
- **유틸리티 메서드:**
1590
-
1591
- - `create_success_result(data: Dict = None) -> StepResult` - 성공 결과 생성
1592
- - `create_error_result(error: str, original_exception: Exception = None) -> StepResult` - 오류 결과 생성
1593
- - `create_skip_result() -> StepResult` - 건너뛰기 결과 생성
1594
-
1595
- #### StepResult
1596
-
1597
- 워크플로우 단계 실행에서 반환되는 결과 객체입니다.
1598
-
1599
- **속성:**
1600
-
1601
- - `success: bool` - 단계가 성공적으로 실행되었는지 여부
1602
- - `data: Dict[str, Any]` - 단계 결과 데이터
1603
- - `error: str` - 단계가 실패한 경우 오류 메시지
1604
- - `rollback_data: Dict[str, Any]` - 롤백에 필요한 데이터
1605
- - `skipped: bool` - 단계가 건너뛰어졌는지 여부
1606
- - `original_exception: Optional[Exception]` - 디버깅을 위한 원본 예외
1607
- - `timestamp: datetime` - 실행 타임스탬프
1608
-
1609
- **사용법:**
1610
-
1611
- ```python
1612
- # 불린 평가
1613
- if step_result:
1614
- # 단계가 성공함
1615
- process_success(step_result.data)
1616
- ```
1617
-
1618
- #### 구체적인 단계
1619
-
1620
- **InitializeStep** (`name: "initialize"`, `weight: 0.05`)
1621
-
1622
- - 스토리지 연결 및 pathlib 작업 디렉토리 설정
1623
- - 기본 업로드 전제조건 검증
1624
-
1625
- **ProcessMetadataStep** (`name: "process_metadata"`, `weight: 0.05`)
1626
-
1627
- - 제공된 Excel 메타데이터 처리
1628
- - 메타데이터 보안 및 형식 검증
1629
-
1630
- **AnalyzeCollectionStep** (`name: "analyze_collection"`, `weight: 0.05`)
1631
-
1632
- - 데이터 컬렉션 파일 사양 검색 및 검증
1633
- - 파일 구성 규칙 설정
1634
-
1635
- **OrganizeFilesStep** (`name: "organize_files"`, `weight: 0.10`)
1636
-
1637
- - 파일 발견 전략을 사용한 파일 발견
1638
- - 타입 및 사양별 파일 구성
1639
-
1640
- **ValidateFilesStep** (`name: "validate_files"`, `weight: 0.05`)
1641
-
1642
- - 검증 전략을 사용한 파일 검증
1643
- - 보안 및 내용 검사 수행
1644
-
1645
- **UploadFilesStep** (`name: "upload_files"`, `weight: 0.30`)
1646
-
1647
- - 업로드 전략을 사용한 파일 업로드
1648
- - 배치 및 진행률 추적 처리
1649
-
1650
- **GenerateDataUnitsStep** (`name: "generate_data_units"`, `weight: 0.35`)
1651
-
1652
- - 데이터 단위 전략을 사용한 데이터 단위 생성
1653
- - 업로드된 파일을 데이터 단위에 연결
1654
-
1655
- **CleanupStep** (`name: "cleanup"`, `weight: 0.05`)
1656
-
1657
- - 임시 리소스 및 파일 정리
1658
- - 최종 검증 수행
1659
-
1660
- ### 전략 기본 클래스
1661
-
1662
- #### BaseValidationStrategy (추상)
1663
-
1664
- 파일 검증 전략의 기본 클래스입니다.
1665
-
1666
- **추상 메서드:**
1667
-
1668
- - `validate_files(files: List[Path], context: UploadContext) -> bool` - 파일 컬렉션 검증
1669
- - `validate_security(file_path: Path) -> bool` - 개별 파일 보안 검증
1670
-
1671
- #### BaseFileDiscoveryStrategy (추상)
1672
-
1673
- 파일 발견 및 구성 전략의 기본 클래스입니다.
1674
-
1675
- **추상 메서드:**
1676
-
1677
- - `discover_files(path: Path, context: UploadContext) -> List[Path]` - 경로에서 파일 발견
1678
- - `organize_files(files: List[Path], specs: Dict[str, Any], context: UploadContext) -> List[Dict[str, Any]]` - 발견된 파일 구성
1679
-
1680
- #### BaseMetadataStrategy (추상)
1681
-
1682
- 메타데이터 처리 전략의 기본 클래스입니다.
1683
-
1684
- **추상 메서드:**
1685
-
1686
- - `process_metadata(context: UploadContext) -> Dict[str, Any]` - 컨텍스트에서 메타데이터 처리
1687
- - `extract_metadata(file_path: Path) -> Dict[str, Any]` - 파일에서 메타데이터 추출
1688
-
1689
- #### BaseUploadStrategy (추상)
1690
-
1691
- 파일 업로드 전략의 기본 클래스입니다.
1692
-
1693
- **추상 메서드:**
1694
-
1695
- - `upload_files(files: List[Dict[str, Any]], context: UploadContext) -> List[Dict[str, Any]]` - 파일 컬렉션 업로드
1696
- - `upload_batch(batch: List[Dict[str, Any]], context: UploadContext) -> List[Dict[str, Any]]` - 파일 배치 업로드
1697
-
1698
- #### BaseDataUnitStrategy (추상)
1699
-
1700
- 데이터 단위 생성 전략의 기본 클래스입니다.
1701
-
1702
- **추상 메서드:**
1703
-
1704
- - `generate_data_units(files: List[Dict[str, Any]], context: UploadContext) -> List[Dict[str, Any]]` - 데이터 단위 생성
1705
- - `create_data_unit_batch(batch: List[Dict[str, Any]], context: UploadContext) -> List[Dict[str, Any]]` - 데이터 단위 배치 생성
1706
-
1707
- ### 레거시 컴포넌트
1708
-
1709
- #### UploadRun
1710
-
1711
- 업로드 작업을 위한 전문 실행 관리 (레거시에서 변경 없음).
1712
-
1713
- **로깅 메서드:**
1714
-
1715
- - `log_message_with_code(code, *args, level=None)` - 타입 안전 로깅
1716
- - `log_upload_event(code, *args, level=None)` - 업로드 특정 이벤트
1717
-
1718
- **중첩 모델:**
1719
-
1720
- - `UploadEventLog` - 업로드 이벤트 로깅
1721
- - `DataFileLog` - 데이터 파일 처리 로그
1722
- - `DataUnitLog` - 데이터 단위 생성 로그
1723
- - `TaskLog` - 작업 실행 로그
1724
- - `MetricsRecord` - 메트릭 추적
1725
-
1726
- #### UploadParams
1727
-
1728
- Pydantic 통합을 포함한 매개변수 검증 모델 (레거시에서 변경 없음).
1729
-
1730
- **필수 매개변수:**
1731
-
1732
- - `name: str` - 업로드 이름
1733
- - `path: str` - 소스 경로
1734
- - `storage: int` - 스토리지 ID
1735
- - `data_collection: int` - 데이터 컬렉션 ID
1736
-
1737
- **선택적 매개변수:**
1738
-
1739
- - `description: str | None = None` - 업로드 설명
1740
- - `project: int | None = None` - 프로젝트 ID
1741
- - `excel_metadata_path: str | None = None` - Excel 메타데이터 파일 경로
1742
- - `is_recursive: bool = False` - 재귀적 파일 발견
1743
- - `max_file_size_mb: int = 50` - 최대 파일 크기
1744
- - `creating_data_unit_batch_size: int = 100` - 데이터 단위 배치 크기
1745
- - `use_async_upload: bool = True` - 비동기 업로드 처리
1746
-
1747
- **검증 기능:**
1748
-
1749
- - storage/data_collection/project에 대한 실시간 API 검증
1750
- - 문자열 정화 및 길이 검증
1751
- - 타입 검사 및 변환
1752
- - 사용자 정의 검증자 메서드
1753
-
1754
- ### 유틸리티 클래스
1755
-
1756
- #### ExcelSecurityConfig
1757
-
1758
- Excel 파일 처리를 위한 보안 구성입니다.
1759
-
1760
- **구성 속성:**
1761
-
1762
- - 파일 크기 및 메모리 제한
1763
- - 행 및 열 개수 제한
1764
- - 문자열 길이 제한
1765
- - 환경 변수 오버라이드
1766
-
1767
- #### ExcelMetadataUtils
1768
-
1769
- Excel 메타데이터 처리를 위한 유틸리티 메서드입니다.
1770
-
1771
- **주요 메서드:**
1772
-
1773
- - `validate_and_truncate_string()` - 문자열 정화
1774
- - `is_valid_filename_length()` - 파일명 검증
1775
-
1776
- #### PathAwareJSONEncoder
1777
-
1778
- Path 및 datetime 객체를 위한 사용자 정의 JSON 인코더입니다.
1779
-
1780
- **지원되는 타입:**
1781
-
1782
- - Path 객체 (문자열로 변환)
1783
- - Datetime 객체 (ISO 형식)
1784
- - 표준 JSON 직렬화 가능한 타입
1785
-
1786
- ### 열거형
1787
-
1788
- #### LogCode
1789
-
1790
- 업로드 작업을 위한 타입 안전 로깅 코드입니다.
1791
-
1792
- **카테고리:**
1793
-
1794
- - 검증 코드 (VALIDATION_FAILED, STORAGE_VALIDATION_FAILED)
1795
- - 파일 처리 코드 (NO_FILES_FOUND, FILES_DISCOVERED)
1796
- - Excel 처리 코드 (EXCEL_SECURITY_VIOLATION, EXCEL_PARSING_ERROR)
1797
- - 진행률 코드 (UPLOADING_DATA_FILES, GENERATING_DATA_UNITS)
1798
-
1799
- #### UploadStatus
1800
-
1801
- 업로드 처리 상태 열거형입니다.
1802
-
1803
- **값:**
1804
-
1805
- - `SUCCESS = 'success'` - 작업이 성공적으로 완료됨
1806
- - `FAILED = 'failed'` - 작업이 오류로 실패함
1807
-
1808
- ### 예외
1809
-
1810
- #### ExcelSecurityError
1811
-
1812
- Excel 파일이 보안 제약을 위반할 때 발생합니다.
1813
-
1814
- **일반적인 원인:**
1815
-
1816
- - 파일 크기가 제한을 초과함
1817
- - 메모리 사용량 추정이 너무 높음
1818
- - 내용 보안 위반
1819
-
1820
- #### ExcelParsingError
1821
-
1822
- Excel 파일을 파싱할 수 없을 때 발생합니다.
1823
-
1824
- **일반적인 원인:**
1825
-
1826
- - 파일 형식 손상
1827
- - 유효하지 않은 Excel 구조
1828
- - 필요한 열 누락
1829
- - 내용 파싱 실패
1830
-
1831
- ## 모범 사례
1832
-
1833
- ### 아키텍처 패턴
1834
-
1835
- 1. **전략 선택**: 사용 사례 요구사항에 따라 적절한 전략을 선택하세요
1836
-
1837
- - 깊은 디렉토리 구조에는 `RecursiveFileDiscoveryStrategy` 사용
1838
- - 표준 파일 검증에는 `BasicValidationStrategy` 사용
1839
- - 큰 파일 세트에는 `AsyncUploadStrategy` 사용
1840
-
1841
- 2. **단계 순서**: 논리적 단계 종속성을 유지하세요
1842
-
1843
- - Initialize → Process Metadata → Analyze Collection → Organize Files → Validate → Upload → Generate Data Units → Cleanup
1844
- - 사용자 정의 단계는 워크플로우의 적절한 지점에 삽입해야 함
1845
-
1846
- 3. **컨텍스트 관리**: 상태 공유를 위해 UploadContext를 활용하세요
1847
- - 다운스트림 단계를 위해 컨텍스트에 중간 결과 저장
1848
- - 단계 간 통신에 컨텍스트 사용
1849
- - 정리 작업을 위해 롤백 데이터 보존
1850
-
1851
- ### 성능 최적화
1852
-
1853
- 1. **배치 처리**: 시스템 리소스를 기반으로 최적의 배치 크기를 구성하세요
1854
-
1855
- ```python
1856
- params = {
1857
- "creating_data_unit_batch_size": 200, # 메모리에 따라 조정
1858
- "upload_batch_size": 10, # 업로드 전략을 위한 사용자 정의 매개변수
1859
- }
1860
- ```
1861
-
1862
- 2. **비동기 작업**: I/O 바인딩 작업에 비동기 처리를 활성화하세요
1863
-
1864
- ```python
1865
- params = {
1866
- "use_async_upload": True, # 네트워크 작업의 더 나은 처리량
1867
- }
1868
- ```
1869
-
1870
- 3. **메모리 관리**: 사용자 정의 전략에서 메모리 사용량을 모니터링하세요
1871
-
1872
- - 모든 파일을 메모리에 로드하지 말고 청크 단위로 처리
1873
- - 큰 파일 컬렉션에 제너레이터 사용
1874
- - Excel 보안 제한을 적절히 구성
1875
-
1876
- 4. **진행률 모니터링**: 자세한 진행률 추적을 구현하세요
1877
- ```python
1878
- # 진행률 업데이트가 포함된 사용자 정의 단계
1879
- def execute(self, context):
1880
- total_files = len(context.organized_files)
1881
- for i, file_info in enumerate(context.organized_files):
1882
- # 파일 처리
1883
- progress = (i + 1) / total_files * 100
1884
- context.update_metrics('custom_step', {'progress': progress})
1885
- ```
1886
-
1887
- ### 보안 고려사항
1888
-
1889
- 1. **입력 검증**: 모든 입력 매개변수 및 파일 경로를 검증하세요
1890
-
1891
- ```python
1892
- # 전략에서 사용자 정의 검증
1893
- def validate_files(self, files, context):
1894
- for file_path in files:
1895
- if not self._is_safe_path(file_path):
1896
- return False
1897
- return True
1898
- ```
1899
-
1900
- 2. **파일 내용 보안**: 내용 기반 보안 검사를 구현하세요
1901
-
1902
- - 악성 파일 서명 스캔
1903
- - 파일 헤더가 확장자와 일치하는지 검증
1904
- - 임베디드 실행 파일 검사
1905
-
1906
- 3. **Excel 보안**: 적절한 보안 제한을 구성하세요
1907
-
1908
- ```python
1909
- import os
1910
- os.environ['EXCEL_MAX_FILE_SIZE_MB'] = '10'
1911
- os.environ['EXCEL_MAX_MEMORY_MB'] = '30'
1912
- ```
1913
-
1914
- 4. **경로 정화**: 모든 파일 경로를 검증하고 정화하세요
1915
- - 경로 순회 공격 방지
1916
- - 파일 확장자 검증
1917
- - 파일 권한 확인
1918
-
1919
- ### 오류 처리 및 복구
1920
-
1921
- 1. **우아한 저하**: 부분 실패 시나리오를 위해 설계하세요
1922
-
1923
- ```python
1924
- class RobustUploadStrategy(BaseUploadStrategy):
1925
- def upload_files(self, files, context):
1926
- successful_uploads = []
1927
- failed_uploads = []
1928
-
1929
- for file_info in files:
1930
- try:
1931
- result = self._upload_file(file_info)
1932
- successful_uploads.append(result)
1933
- except Exception as e:
1934
- failed_uploads.append({'file': file_info, 'error': str(e)})
1935
- # 완전히 실패하지 말고 다른 파일로 계속 진행
1936
-
1937
- # 부분 결과로 컨텍스트 업데이트
1938
- context.add_uploaded_files(successful_uploads)
1939
- if failed_uploads:
1940
- context.add_error(f"Failed to upload {len(failed_uploads)} files")
1941
-
1942
- return successful_uploads
1943
- ```
1944
-
1945
- 2. **롤백 설계**: 포괄적인 롤백 전략을 구현하세요
1946
-
1947
- ```python
1948
- def rollback(self, context):
1949
- # 작업의 역순으로 정리
1950
- if hasattr(self, '_created_temp_files'):
1951
- for temp_file in self._created_temp_files:
1952
- try:
1953
- temp_file.unlink()
1954
- except Exception:
1955
- pass # 정리 문제로 인한 롤백 실패 방지
1956
- ```
1957
-
1958
- 3. **자세한 로깅**: 디버깅을 위한 구조화된 로깅을 사용하세요
1959
-
1960
- ```python
1961
- def execute(self, context):
1962
- try:
1963
- context.run.log_message_with_code(
1964
- 'CUSTOM_STEP_STARTED',
1965
- {'step': self.name, 'file_count': len(context.organized_files)}
1966
- )
1967
- # 여기에 단계 로직
1968
- except Exception as e:
1969
- context.run.log_message_with_code(
1970
- 'CUSTOM_STEP_FAILED',
1971
- {'step': self.name, 'error': str(e)},
1972
- level=Context.DANGER
1973
- )
1974
- raise
1975
- ```
1976
-
1977
- ### 개발 가이드라인
1978
-
1979
- 1. **사용자 정의 전략 개발**: 확립된 패턴을 따르세요
1980
-
1981
- ```python
1982
- # 항상 적절한 기본 클래스를 확장
1983
- class MyCustomStrategy(BaseValidationStrategy):
1984
- def __init__(self, config=None):
1985
- self.config = config or {}
1986
-
1987
- def validate_files(self, files, context):
1988
- # 검증 로직 구현
1989
- return True
1990
-
1991
- def validate_security(self, file_path):
1992
- # 보안 검증 구현
1993
- return True
1994
- ```
1995
-
1996
- 2. **테스트 전략**: 포괄적인 테스트 커버리지
1997
-
1998
- ```python
1999
- # 성공 및 실패 시나리오 모두 테스트
2000
- class TestCustomStrategy:
2001
- def test_success_case(self):
2002
- strategy = MyCustomStrategy()
2003
- result = strategy.validate_files([Path('valid_file.txt')], mock_context)
2004
- assert result is True
2005
-
2006
- def test_security_failure(self):
2007
- strategy = MyCustomStrategy()
2008
- result = strategy.validate_security(Path('malware.exe'))
2009
- assert result is False
2010
-
2011
- def test_rollback_cleanup(self):
2012
- step = MyCustomStep()
2013
- step.rollback(mock_context)
2014
- # 정리가 수행되었는지 확인
2015
- ```
2016
-
2017
- 3. **확장 지점**: 확장성을 위해 팩토리 패턴 사용
2018
-
2019
- ```python
2020
- class CustomStrategyFactory(StrategyFactory):
2021
- def create_validation_strategy(self, params, context=None):
2022
- validation_type = params.get('validation_type', 'basic')
2023
-
2024
- strategy_map = {
2025
- 'basic': BasicValidationStrategy,
2026
- 'strict': StrictValidationStrategy,
2027
- 'custom': MyCustomValidationStrategy,
2028
- }
2029
-
2030
- strategy_class = strategy_map.get(validation_type, BasicValidationStrategy)
2031
- return strategy_class(params)
2032
- ```
2033
-
2034
- 4. **구성 관리**: 환경 변수 및 매개변수 사용
2035
-
2036
- ```python
2037
- class ConfigurableStep(BaseStep):
2038
- def __init__(self):
2039
- # 런타임 구성 허용
2040
- self.batch_size = int(os.getenv('STEP_BATCH_SIZE', '50'))
2041
- self.timeout = int(os.getenv('STEP_TIMEOUT_SECONDS', '300'))
2042
-
2043
- def execute(self, context):
2044
- # 구성된 값 사용
2045
- batch_size = context.get_param('step_batch_size', self.batch_size)
2046
- timeout = context.get_param('step_timeout', self.timeout)
2047
- ```
2048
-
2049
- ### 피해야 할 안티패턴
2050
-
2051
- 1. **강한 결합**: 전략을 특정 구현에 결합하지 마세요
2052
- 2. **상태 변형**: update() 메서드 외부에서 컨텍스트 상태를 직접 수정하지 마세요
2053
- 3. **예외 삼킴**: 적절한 처리 없이 예외를 잡아서 무시하지 마세요
2054
- 4. **블로킹 작업**: 진행률 업데이트 없이 장시간 실행되는 동기 작업을 수행하지 마세요
2055
- 5. **메모리 누수**: 단계 인스턴스에서 큰 객체에 대한 참조를 보유하지 마세요
2056
-
2057
- ### 문제 해결 가이드
2058
-
2059
- 1. **단계 실패**: 단계 실행 순서 및 종속성 확인
2060
- 2. **전략 문제**: 전략 팩토리 구성 및 매개변수 전달 확인
2061
- 3. **컨텍스트 문제**: 적절한 컨텍스트 업데이트 및 상태 관리 확인
2062
- 4. **롤백 실패**: 멱등적 롤백 작업 설계
2063
- 5. **성능 문제**: 배치 크기 및 비동기 작업 사용량 프로파일링
2064
-
2065
- ### 마이그레이션 체크리스트
2066
-
2067
- 레거시 구현에서 업그레이드할 때:
2068
-
2069
- - [ ] 매개변수 이름을 `collection`에서 `data_collection`으로 업데이트
2070
- - [ ] 호환성을 위한 기존 워크플로우 테스트
2071
- - [ ] 새 아키텍처 기회에 대한 사용자 정의 확장 검토
2072
- - [ ] 새 롤백 기능을 활용하도록 오류 처리 업데이트
2073
- - [ ] 특수 요구사항에 대한 사용자 정의 전략 구현 고려
2074
- - [ ] 새 워크플로우 단계를 검증하도록 테스트 케이스 업데이트
2075
- - [ ] 향상된 정보에 대한 로깅 및 메트릭 수집 검토
2076
-
2077
- BaseUploader 템플릿을 사용한 커스텀 업로드 플러그인 개발에 대한 자세한 정보는 [업로드 템플릿 개발하기](./developing-upload-template.md) 가이드를 참조하세요.