98 lines
3.1 KiB
Python
98 lines
3.1 KiB
Python
"""
|
|
تسکهای Celery برای واکشی دادههای خاک.
|
|
"""
|
|
|
|
from decimal import Decimal
|
|
|
|
from config.celery import app
|
|
from django.apps import apps
|
|
from django.db import transaction
|
|
|
|
from .models import SoilDepthData, SoilLocation
|
|
from .soil_adapters import DEPTHS
|
|
|
|
try:
|
|
import requests
|
|
except ImportError: # pragma: no cover - handled in stripped envs
|
|
RequestException = Exception
|
|
else:
|
|
RequestException = requests.RequestException
|
|
|
|
|
|
def fetch_soil_data_for_coordinates(
|
|
latitude: float,
|
|
longitude: float,
|
|
task_id: str = "",
|
|
progress_callback=None,
|
|
):
|
|
"""
|
|
واکشی سنکرون داده خاک برای مختصات دادهشده و ذخیره در DB.
|
|
این helper هم توسط Celery task و هم توسط endpointهای sync استفاده میشود.
|
|
"""
|
|
lat = Decimal(str(round(float(latitude), 6)))
|
|
lon = Decimal(str(round(float(longitude), 6)))
|
|
adapter = apps.get_app_config("location_data").get_soil_data_adapter()
|
|
|
|
with transaction.atomic():
|
|
location, created = SoilLocation.objects.select_for_update().get_or_create(
|
|
latitude=lat,
|
|
longitude=lon,
|
|
defaults={"task_id": task_id},
|
|
)
|
|
if not created and task_id:
|
|
location.task_id = task_id
|
|
location.save(update_fields=["task_id"])
|
|
|
|
for index, depth in enumerate(DEPTHS):
|
|
if progress_callback is not None:
|
|
progress_callback(
|
|
state="PROGRESS",
|
|
meta={
|
|
"current": index + 1,
|
|
"total": len(DEPTHS),
|
|
"message": f"در حال واکشی عمق {depth}...",
|
|
},
|
|
)
|
|
fields = adapter.fetch_depth_fields(float(lon), float(lat), depth)
|
|
with transaction.atomic():
|
|
SoilDepthData.objects.update_or_create(
|
|
soil_location=location,
|
|
depth_label=depth,
|
|
defaults=fields,
|
|
)
|
|
|
|
if task_id:
|
|
with transaction.atomic():
|
|
location.task_id = ""
|
|
location.save(update_fields=["task_id"])
|
|
|
|
return {
|
|
"status": "completed",
|
|
"location_id": location.id,
|
|
"depths": DEPTHS,
|
|
}
|
|
|
|
|
|
@app.task(bind=True)
|
|
def fetch_soil_data_task(self, latitude: float, longitude: float):
|
|
"""
|
|
واکشی دادههای خاک برای مختصات دادهشده و ذخیره در DB.
|
|
برای هر عمق (0-5cm, 5-15cm, 15-30cm) یک ریکوئست/شبیهسازی جدا انجام میشود.
|
|
"""
|
|
try:
|
|
return fetch_soil_data_for_coordinates(
|
|
latitude=latitude,
|
|
longitude=longitude,
|
|
task_id=self.request.id,
|
|
progress_callback=self.update_state,
|
|
)
|
|
except RequestException as exc:
|
|
lat = Decimal(str(round(float(latitude), 6)))
|
|
lon = Decimal(str(round(float(longitude), 6)))
|
|
location = SoilLocation.objects.filter(latitude=lat, longitude=lon).first()
|
|
return {
|
|
"status": "error",
|
|
"location_id": getattr(location, "id", None),
|
|
"error": str(exc),
|
|
}
|