UPDATE
This commit is contained in:
@@ -0,0 +1,446 @@
|
||||
# گزارش تحلیل خطای `location_data` برای Remote Sensing Run
|
||||
|
||||
این سند بر اساس payload دریافتی از endpoint زیر تهیه شده است:
|
||||
|
||||
- `GET /api/location-data/remote-sensing/runs/{task_id}/status/`
|
||||
|
||||
نمونه run بررسیشده:
|
||||
|
||||
- `task_id`: `02959179-63b2-4388-bb2e-a4d79176eca2`
|
||||
- `run.id`: `6`
|
||||
- بازه زمانی: `2026-04-09` تا `2026-05-09`
|
||||
- وضعیت API: `failed`
|
||||
- وضعیت Celery: `RETRY`
|
||||
|
||||
---
|
||||
|
||||
## 1) خلاصه خیلی کوتاه
|
||||
|
||||
این run تا مرحله واکشی metricها و ذخیره observationها جلو رفته، اما در مرحله ساخت subdivision دادهمحور شکست خورده است.
|
||||
|
||||
خطای نهایی:
|
||||
|
||||
- `هیچ observation قابل استفادهای برای خوشهبندی باقی نماند.`
|
||||
|
||||
این خطا در کد دقیقاً زمانی رخ میدهد که سیستم بعد از بارگذاری observationها، هیچ ردیفی را برای clustering قابل استفاده تشخیص ندهد.
|
||||
|
||||
مسیر کد:
|
||||
|
||||
- `location_data/tasks.py`
|
||||
- `location_data/data_driven_subdivision.py`
|
||||
|
||||
---
|
||||
|
||||
## 2) جدول مدلها / جدولهای درگیر
|
||||
|
||||
| مدل | جدول Django | نقش |
|
||||
|---|---|---|
|
||||
| `SoilLocation` | `location_data_soillocation` | اطلاعات location و farm boundary |
|
||||
| `BlockSubdivision` | `location_data_blocksubdivision` | تقسیمبندی بلوک/مزرعه |
|
||||
| `RemoteSensingRun` | `location_data_remotesensingrun` | وضعیت اجرای pipeline سنجشازدور |
|
||||
| `AnalysisGridCell` | `location_data_analysisgridcell` | سلولهای شبکه تحلیلی |
|
||||
| `AnalysisGridObservation` | `location_data_analysisgridobservation` | مقادیر metricها برای هر cell |
|
||||
| `RemoteSensingSubdivisionResult` | `location_data_remotesensingsubdivisionresult` | نتیجه clustering و subdivision نهایی |
|
||||
| `RemoteSensingClusterAssignment` | `location_data_remotesensingclusterassignment` | نسبت هر cell به cluster |
|
||||
|
||||
---
|
||||
|
||||
## 3) جدول معنی فیلدهای سطح اول response
|
||||
|
||||
| فیلد | مقدار نمونه | توضیح |
|
||||
|---|---|---|
|
||||
| `code` | `200` | پاسخ HTTP موفق از API؛ لزوماً به معنای موفق بودن task نیست |
|
||||
| `msg` | `success` | پیام wrapper API |
|
||||
| `data.status` | `failed` | وضعیت client-facing run |
|
||||
| `data.source` | `database` | payload از دادههای ذخیرهشده در DB ساخته شده |
|
||||
| `data.task_id` | UUID | شناسه Celery task |
|
||||
| `data.run` | object | snapshot اصلی run |
|
||||
| `data.task` | object | جزئیات stageها، timestamps و وضعیت Celery |
|
||||
|
||||
---
|
||||
|
||||
## 4) جدول معنی فیلدهای `run`
|
||||
|
||||
| فیلد | مقدار نمونه | توضیح |
|
||||
|---|---|---|
|
||||
| `id` | `6` | شناسه رکورد run در DB |
|
||||
| `block_code` | `""` | خالی یعنی کل مزرعه، نه یک بلوک خاص |
|
||||
| `chunk_size_sqm` | `900` | اندازه هر cell به متر مربع |
|
||||
| `temporal_start` | `2026-04-09` | شروع بازه تحلیل |
|
||||
| `temporal_end` | `2026-05-09` | پایان بازه تحلیل |
|
||||
| `status` | `failure` | مقدار خام DB |
|
||||
| `status_label` | `failed` | نسخه نرمالشده برای client |
|
||||
| `pipeline_status` | `failed` | تکرار client-facing status |
|
||||
| `stage` | `observations_persisted` | آخرین stage ذخیرهشده در metadata |
|
||||
| `selected_features` | `ndvi`, `ndwi`, `lst_c`, `soil_vv_db`, `dem_m`, `slope_deg` | featureهایی که pipeline فکر میکند برای clustering لازماند |
|
||||
| `requested_cluster_count` | `null` | تعداد cluster صریح از کاربر نیامده و الگوریتم باید تصمیم بگیرد |
|
||||
| `error_message` | متن فارسی خطا | خطای نهایی ثبتشده روی run |
|
||||
| `started_at` | timestamp | زمان شروع واقعی run |
|
||||
| `finished_at` | timestamp | زمان ثبت failure روی run |
|
||||
| `created_at` | timestamp | زمان ایجاد رکورد run |
|
||||
| `updated_at` | timestamp | آخرین بهروزرسانی رکورد run |
|
||||
|
||||
---
|
||||
|
||||
## 5) جدول معنی فیلدهای `run.metadata`
|
||||
|
||||
| فیلد | توضیح |
|
||||
|---|---|
|
||||
| `scope` | scope اجرای تحلیل؛ در این نمونه `all_blocks` |
|
||||
| `stage` | stage فعلی/آخر ذخیرهشده |
|
||||
| `task_id` | شناسه Celery task |
|
||||
| `pipeline.name` | نام pipeline |
|
||||
| `pipeline.version` | نسخه pipeline |
|
||||
| `farm_uuid` | شناسه مزرعه |
|
||||
| `timestamps` | زمان ورود به هر stage |
|
||||
| `status_label` | وضعیت client-facing ذخیرهشده در metadata |
|
||||
| `requested_via` | مبدا درخواست؛ در این نمونه `api` |
|
||||
| `stage_details` | جزئیات هر stage |
|
||||
| `failure_reason` | دلیل نهایی ثبت failure |
|
||||
| `selected_features` | featureهای مورد استفاده برای clustering |
|
||||
| `requested_cluster_count` | cluster count درخواستی، اگر وجود داشته باشد |
|
||||
|
||||
---
|
||||
|
||||
## 6) جدول معنی stageها در این run
|
||||
|
||||
| stage | وضعیت مشاهدهشده | معنی |
|
||||
|---|---|---|
|
||||
| `queued` | completed | task در صف قرار گرفته |
|
||||
| `preparing_analysis_grid` | completed | آمادهسازی grid تحلیلی |
|
||||
| `analysis_grid_ready` | completed | grid سلولها آماده بوده |
|
||||
| `analysis_cells_selected` | completed | 12 سلول برای پردازش انتخاب شدهاند |
|
||||
| `fetching_remote_metrics` | completed | metricها از openEO درخواست شدهاند |
|
||||
| `remote_metrics_fetched` | completed | jobهای openEO تمام شدهاند |
|
||||
| `observations_persisted` | failed | observationها ذخیره شدهاند ولی pipeline بعد از این مرحله fail شده |
|
||||
| `failed` | completed | stage شکست نهایی ثبت شده |
|
||||
|
||||
نکته مهم:
|
||||
|
||||
- در payload فعلی، `run.stage` هنوز `observations_persisted` است اما `data.status` برابر `failed` است.
|
||||
- این یعنی status و stage با هم perfectly sync نیستند.
|
||||
|
||||
---
|
||||
|
||||
## 7) جدول معنی `stage_details`
|
||||
|
||||
### 7.1) `preparing_analysis_grid`
|
||||
|
||||
| فیلد | توضیح |
|
||||
|---|---|
|
||||
| `block_code` | بلوک هدف |
|
||||
| `temporal_extent.start_date` | شروع بازه |
|
||||
| `temporal_extent.end_date` | پایان بازه |
|
||||
|
||||
### 7.2) `analysis_grid_ready`
|
||||
|
||||
| فیلد | توضیح |
|
||||
|---|---|
|
||||
| `grid_summary.created` | آیا grid همین run ساخته شده یا از قبل وجود داشته |
|
||||
| `grid_summary.block_code` | کد بلوک |
|
||||
| `grid_summary.total_count` | تعداد کل cellها |
|
||||
| `grid_summary.created_count` | تعداد cell تازه ایجادشده |
|
||||
| `grid_summary.chunk_size_sqm` | اندازه cell |
|
||||
| `grid_summary.existing_count` | تعداد cellهای موجود از قبل |
|
||||
|
||||
### 7.3) `analysis_cells_selected`
|
||||
|
||||
| فیلد | توضیح |
|
||||
|---|---|
|
||||
| `force_refresh` | آیا cache نادیده گرفته شده |
|
||||
| `total_cell_count` | تعداد کل cellها |
|
||||
| `existing_cell_count` | تعداد cellهایی که داده از قبل داشتهاند |
|
||||
| `cell_count_to_process` | تعداد cellهایی که باید پردازش شوند |
|
||||
|
||||
### 7.4) `fetching_remote_metrics`
|
||||
|
||||
| فیلد | توضیح |
|
||||
|---|---|
|
||||
| `target_cells` | لیست cellهای هدف |
|
||||
| `requested_cell_count` | تعداد cellهای هدف |
|
||||
| `metric_progress.total_metrics` | تعداد metricهایی که pipeline انتظار دارد |
|
||||
| `metric_progress.completed_metric_count` | تعداد metricهای کاملشده |
|
||||
| `metric_progress.completed_metrics` | metricهای کاملشده واقعی |
|
||||
| `metric_progress.failed_metrics` | metricهای fail شده |
|
||||
| `metric_progress.states` | وضعیت هر metric از نگاه progress tracker |
|
||||
|
||||
### 7.5) `remote_metrics_fetched`
|
||||
|
||||
| فیلد | توضیح |
|
||||
|---|---|
|
||||
| `failed_metric_count` | تعداد metric fail شده |
|
||||
| `service_metadata.backend` | backend مورد استفاده |
|
||||
| `service_metadata.job_refs` | job id هر metric در openEO |
|
||||
| `service_metadata.backend_url` | آدرس backend |
|
||||
| `service_metadata.failed_metrics` | خطاهای metric-level |
|
||||
| `service_metadata.collections_used` | collectionهای مصرفشده |
|
||||
|
||||
### 7.6) `observations_persisted`
|
||||
|
||||
| فیلد | توضیح |
|
||||
|---|---|
|
||||
| `created_count` | تعداد observation ساختهشده |
|
||||
| `updated_count` | تعداد observation بهروزشده |
|
||||
|
||||
---
|
||||
|
||||
## 8) جدول معنی `task`
|
||||
|
||||
| فیلد | مقدار نمونه | توضیح |
|
||||
|---|---|---|
|
||||
| `current_stage` | `observations_persisted` | stage فعلی/آخرین stage ثبتشده |
|
||||
| `current_stage_details` | `created_count=12`, `updated_count=0` | جزئیات stage جاری |
|
||||
| `timestamps` | object | timeline کامل stageها |
|
||||
| `stages` | list | نسخه ترتیبی از stageها |
|
||||
| `metric_progress` | object | وضعیت پیشرفت metricها |
|
||||
| `failure_reason` | متن فارسی | خطای ثبتشده |
|
||||
| `celery.state` | `RETRY` | Celery task هنوز final نشده و در retry است |
|
||||
| `celery.ready` | `false` | نتیجه نهایی هنوز آماده نیست |
|
||||
| `celery.successful` | `false` | task هنوز success نشده |
|
||||
| `celery.failed` | `false` | task هنوز fail نهایی نشده |
|
||||
| `celery.info` | متن خطا | پیام retry فعلی Celery |
|
||||
|
||||
---
|
||||
|
||||
## 9) دلیل دقیق خطا
|
||||
|
||||
دلیل مستقیم خطا از خود کد:
|
||||
|
||||
- در `location_data/data_driven_subdivision.py` اگر بعد از ساخت dataset، هیچ observation قابل استفاده برای clustering باقی نماند، این exception پرتاب میشود:
|
||||
- `هیچ observation قابل استفادهای برای خوشهبندی باقی نماند.`
|
||||
|
||||
این یعنی pipeline به این نقطه رسیده:
|
||||
|
||||
1. cellها ساخته شدهاند
|
||||
2. metricها از openEO درخواست شدهاند
|
||||
3. observationها در DB ذخیره شدهاند
|
||||
4. اما در زمان ساخت dataset برای clustering، ردیف قابل مصرفی پیدا نشده است
|
||||
|
||||
### معنی عملی این خطا
|
||||
|
||||
یعنی برای همه observationهای این run، سیستم نتوانسته feature vector قابل استفاده بسازد.
|
||||
|
||||
در کد فعلی، observation وقتی از clustering حذف میشود که:
|
||||
|
||||
- همه featureهای انتخابشده برای آن observation برابر `None` باشند
|
||||
|
||||
پس این خطا معمولاً یعنی:
|
||||
|
||||
- یا تمام metricهای لازم برای همه cellها `null` شدهاند
|
||||
- یا feature set انتخابی با دادههایی که واقعاً ذخیره شدهاند mismatch دارد
|
||||
- یا persistence / selection طوری انجام شده که clustering به داده قابل استفاده دسترسی پیدا نکرده است
|
||||
|
||||
---
|
||||
|
||||
## 10) محتملترین علتها برای همین run
|
||||
|
||||
### علت 1: featureهای حذفشده هنوز در pipeline زنده هستند
|
||||
|
||||
در payload میبینیم:
|
||||
|
||||
- `selected_features` هنوز شامل `dem_m` و `slope_deg` است
|
||||
- اما در `location_data/openeo_service.py` این metricها از محاسبه حذف شدهاند
|
||||
|
||||
نتیجه:
|
||||
|
||||
- API و metadata هنوز فکر میکنند این دو feature بخشی از clustering هستند
|
||||
- ولی openEO دیگر آنها را تولید نمیکند
|
||||
- بنابراین در observationها این فیلدها عملاً `None` میمانند
|
||||
|
||||
نکته مهم:
|
||||
|
||||
- فقط `None` بودن `dem_m` و `slope_deg` بهتنهایی برای تولید این خطا کافی نیست
|
||||
- اما این mismatch یکی از مهمترین نشانههای ناسازگاری pipeline است
|
||||
|
||||
### علت 2: metricهای اصلی احتمالاً برای همه cellها مقدار قابل استفاده نداشتهاند
|
||||
|
||||
چون این خطا فقط وقتی رخ میدهد که هیچ observation usable باقی نماند، محتمل است که برای همه 12 cell:
|
||||
|
||||
- `ndvi`
|
||||
- `ndwi`
|
||||
- `lst_c`
|
||||
- `soil_vv_db`
|
||||
|
||||
هم عملاً `None` شده باشند یا آنطور که clustering انتظار دارد قابل مصرف نبوده باشند.
|
||||
|
||||
این حالت ممکن است از اینجا آمده باشد:
|
||||
|
||||
- داده خام provider برای این محدوده/بازه تهی یا نامعتبر بوده
|
||||
- masking یا aggregation مقدار usable تولید نکرده
|
||||
- یا در persistence، featureهای محاسبهشده بهدرستی به ستونهای clustering نرسیدهاند
|
||||
|
||||
### علت 3: progress tracker با metricهای واقعی sync نیست
|
||||
|
||||
در payload:
|
||||
|
||||
- `completed_metrics` شامل `soil_vv` است
|
||||
- ولی `states` شامل `soil_vv_db` به حالت `pending` است
|
||||
|
||||
یعنی tracker با metric واقعی اجراشده sync نیست:
|
||||
|
||||
- metric واقعی remote: `soil_vv`
|
||||
- metric مشتقشده محلی: `soil_vv_db`
|
||||
|
||||
این باعث میشود progress ظاهراً ناقص دیده شود، حتی وقتی داده remote کامل شده است.
|
||||
|
||||
### علت 4: وضعیت DB و Celery با هم متناقضاند
|
||||
|
||||
در payload:
|
||||
|
||||
- `data.status = failed`
|
||||
- ولی `task.celery.state = RETRY`
|
||||
|
||||
یعنی:
|
||||
|
||||
- از نظر DB، run شکست خورده ثبت شده
|
||||
- از نظر Celery، task هنوز در حال retry است و failure نهایی نشده
|
||||
|
||||
این برای client گیجکننده است، چون معلوم نیست باید run را تمامشده و fail شده بداند یا منتظر retry بماند.
|
||||
|
||||
---
|
||||
|
||||
## 11) مشکلات فعلی `location_data` که از کد مشخص هستند
|
||||
|
||||
### مشکل 1: `DEFAULT_CLUSTER_FEATURES` هنوز metricهای حذفشده را نگه داشته
|
||||
|
||||
فایل:
|
||||
|
||||
- `location_data/data_driven_subdivision.py`
|
||||
|
||||
وضعیت فعلی:
|
||||
|
||||
- `dem_m`
|
||||
- `slope_deg`
|
||||
|
||||
هنوز داخل `DEFAULT_CLUSTER_FEATURES` هستند.
|
||||
|
||||
اثر:
|
||||
|
||||
- `selected_features` اشتباه در run metadata
|
||||
- progress tracker اشتباه
|
||||
- clustering contract قدیمی باقی میماند
|
||||
|
||||
### مشکل 2: serializer و summary هنوز `dem_m` و `slope_deg` را به API برمیگردانند
|
||||
|
||||
فایلها:
|
||||
|
||||
- `location_data/serializers.py`
|
||||
- `location_data/views.py`
|
||||
|
||||
اثر:
|
||||
|
||||
- response API هنوز metricهای حذفشده را نمایش میدهد
|
||||
- summary میانگین `dem_m_mean` و `slope_deg_mean` میسازد
|
||||
- مصرفکننده API فکر میکند این metricها هنوز پشتیبانی میشوند
|
||||
|
||||
### مشکل 3: `_upsert_grid_observations` هنوز فیلدهای حذفشده را persist میکند
|
||||
|
||||
فایل:
|
||||
|
||||
- `location_data/tasks.py`
|
||||
|
||||
اثر:
|
||||
|
||||
- ستونهای `dem_m` و `slope_deg` همچنان نوشته میشوند، اما عملاً با `None`
|
||||
- metadata هنوز `slope_supported` را ذخیره میکند، در حالی که openEO service دیگر این مفهوم را برنمیگرداند
|
||||
|
||||
### مشکل 4: progress metricها با metricهای واقعی اجراشده mismatch دارد
|
||||
|
||||
فایل:
|
||||
|
||||
- `location_data/tasks.py`
|
||||
|
||||
نمونه mismatch:
|
||||
|
||||
- remote metric واقعی: `soil_vv`
|
||||
- feature مورد انتظار برای clustering: `soil_vv_db`
|
||||
|
||||
اثر:
|
||||
|
||||
- `completed_metrics` و `states` با هم ناسازگار میشوند
|
||||
- `soil_vv_db` در response به شکل `pending` دیده میشود، با اینکه از `soil_vv` مشتق میشود
|
||||
|
||||
### مشکل 5: stage و status همیشه هماهنگ نیستند
|
||||
|
||||
در payload فعلی:
|
||||
|
||||
- `run.status_label = failed`
|
||||
- `run.stage = observations_persisted`
|
||||
|
||||
اثر:
|
||||
|
||||
- client نمیفهمد خطا دقیقاً در کدام stage رخ داده
|
||||
- `task.current_stage` هم گمراهکننده میشود
|
||||
|
||||
### مشکل 6: DB failure و Celery retry همزمان به client داده میشود
|
||||
|
||||
اثر:
|
||||
|
||||
- API برای یک run همزمان پیام `failed` و `RETRY` میدهد
|
||||
- از نگاه UX، کاربر نمیداند باید retry خودکار را صبر کند یا خطا را final بداند
|
||||
|
||||
---
|
||||
|
||||
## 12) جمعبندی عملی برای همین خطا
|
||||
|
||||
بر اساس payload و کد، نتیجه عملی این است:
|
||||
|
||||
1. openEO jobها برای `ndvi`, `ndwi`, `lst_c`, `soil_vv` اجرا شدهاند
|
||||
2. 12 observation در DB ساخته شدهاند
|
||||
3. pipeline وارد مرحله clustering شده
|
||||
4. clustering هیچ observation usable پیدا نکرده
|
||||
5. run در DB به حالت `failed` رفته
|
||||
6. اما Celery هنوز task را در حالت `RETRY` نگه داشته
|
||||
|
||||
---
|
||||
|
||||
## 13) پیشنهادهای اصلاح
|
||||
|
||||
### اصلاح ضروری
|
||||
|
||||
1. `dem_m` و `slope_deg` را از این نقاط هم حذف کنید:
|
||||
- `location_data/data_driven_subdivision.py`
|
||||
- `location_data/serializers.py`
|
||||
- `location_data/views.py`
|
||||
- `location_data/tasks.py`
|
||||
|
||||
2. `DEFAULT_CLUSTER_FEATURES` را با metricهای واقعی sync کنید:
|
||||
- `ndvi`
|
||||
- `ndwi`
|
||||
- `lst_c`
|
||||
- `soil_vv_db`
|
||||
|
||||
3. progress tracker را طوری اصلاح کنید که:
|
||||
- completion `soil_vv` به completion `soil_vv_db` هم map شود
|
||||
- metricهای حذفشده اصلاً در state دیده نشوند
|
||||
|
||||
4. منطق status endpoint را طوری تنظیم کنید که:
|
||||
- اگر Celery در `RETRY` است، status client نهایی `failed` نباشد
|
||||
- یا حداقل یک فیلد صریح مثل `final_status=false` برگردد
|
||||
|
||||
5. قبل از clustering، یک diagnostic بهتر ذخیره شود:
|
||||
- تعداد observationهای usable
|
||||
- تعداد observationهای all-null
|
||||
- تعداد null برای هر feature
|
||||
|
||||
### اصلاح پیشنهادی برای debug بهتر
|
||||
|
||||
در `stage_details` این موارد اضافه شود:
|
||||
|
||||
- `usable_observation_count`
|
||||
- `all_features_missing_cell_codes`
|
||||
- `feature_null_counts`
|
||||
- `selected_features_effective`
|
||||
|
||||
---
|
||||
|
||||
## 14) نتیجه نهایی
|
||||
|
||||
این run به احتمال زیاد به خاطر ناسازگاری بین featureهای مورد انتظار pipeline و featureهای واقعاً تولید/ذخیرهشده شکست خورده است، و علاوه بر آن چند inconsistency مهم در `location_data` وجود دارد:
|
||||
|
||||
- metricهای حذفشده هنوز در feature contract حضور دارند
|
||||
- progress report با metricهای واقعی sync نیست
|
||||
- DB status و Celery status با هم تناقض دارند
|
||||
- stage نهایی برای failure به شکل واضح و قابل اتکا به client نمایش داده نمیشود
|
||||
|
||||
اگر بخواهید، مرحله بعدی میتواند این باشد که همین موارد را در کد هم اصلاح کنیم، نه فقط مستندسازی.
|
||||
Reference in New Issue
Block a user