Skip to content

Commit 5ddfb23

Browse files
authored
Merge pull request #33 from CMCC-Foundation/feature_18
- Merging feature from Sebastien project (CSV, GeoJSON, raster map apis) - Zarr new feature - Temporal Resample on the fly - Spatial regrid on the fly
2 parents 0c1742d + 628a233 commit 5ddfb23

File tree

18 files changed

+679
-61
lines changed

18 files changed

+679
-61
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ The system has been designed using a cloud-native architecture, based on contain
1010

1111
It uses [geokube](https://github.com/CMCC-Foundation/geokube) as an Analytics Engine to perform geospatial operations.
1212

13-
## Developer Team
13+
## Developers Team
1414

1515
- [Valentina Scardigno](https://github.com/vale95-eng)
1616
- [Gabriele Tramonte](https://github.com/gtramonte)

api/app/endpoint_handlers/dataset.py

Lines changed: 87 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
import pika
44
from typing import Optional
55

6-
from dbmanager.dbmanager import DBManager
6+
from fastapi.responses import FileResponse
7+
8+
from dbmanager.dbmanager import DBManager, RequestStatus
79
from geoquery.geoquery import GeoQuery
810
from geoquery.task import TaskList
911
from datastore.datastore import Datastore, DEFAULT_MAX_REQUEST_SIZE_GB
@@ -18,12 +20,18 @@
1820
from api_utils import make_bytes_readable_dict
1921
from validation import assert_product_exists
2022

23+
from . import request
2124

2225
log = get_dds_logger(__name__)
2326
data_store = Datastore()
2427

2528
MESSAGE_SEPARATOR = os.environ["MESSAGE_SEPARATOR"]
2629

30+
def _is_etimate_enabled(dataset_id, product_id):
31+
if dataset_id in ("sentinel-2",):
32+
return False
33+
return True
34+
2735

2836
@log_execution_time(log)
2937
def get_datasets(user_roles_names: list[str]) -> list[dict]:
@@ -213,7 +221,7 @@ def estimate(
213221

214222
@log_execution_time(log)
215223
@assert_product_exists
216-
def query(
224+
def async_query(
217225
user_id: str,
218226
dataset_id: str,
219227
product_id: str,
@@ -250,21 +258,22 @@ def query(
250258
251259
"""
252260
log.debug("geoquery: %s", query)
253-
estimated_size = estimate(dataset_id, product_id, query, "GB").get("value")
254-
allowed_size = data_store.product_metadata(dataset_id, product_id).get(
255-
"maximum_query_size_gb", DEFAULT_MAX_REQUEST_SIZE_GB
256-
)
257-
if estimated_size > allowed_size:
258-
raise exc.MaximumAllowedSizeExceededError(
259-
dataset_id=dataset_id,
260-
product_id=product_id,
261-
estimated_size_gb=estimated_size,
262-
allowed_size_gb=allowed_size,
263-
)
264-
if estimated_size == 0.0:
265-
raise exc.EmptyDatasetError(
266-
dataset_id=dataset_id, product_id=product_id
261+
if _is_etimate_enabled(dataset_id, product_id):
262+
estimated_size = estimate(dataset_id, product_id, query, "GB").get("value")
263+
allowed_size = data_store.product_metadata(dataset_id, product_id).get(
264+
"maximum_query_size_gb", DEFAULT_MAX_REQUEST_SIZE_GB
267265
)
266+
if estimated_size > allowed_size:
267+
raise exc.MaximumAllowedSizeExceededError(
268+
dataset_id=dataset_id,
269+
product_id=product_id,
270+
estimated_size_gb=estimated_size,
271+
allowed_size_gb=allowed_size,
272+
)
273+
if estimated_size == 0.0:
274+
raise exc.EmptyDatasetError(
275+
dataset_id=dataset_id, product_id=product_id
276+
)
268277
broker_conn = pika.BlockingConnection(
269278
pika.ConnectionParameters(
270279
host=os.getenv("BROKER_SERVICE_HOST", "broker")
@@ -295,6 +304,68 @@ def query(
295304
broker_conn.close()
296305
return request_id
297306

307+
@log_execution_time(log)
308+
@assert_product_exists
309+
def sync_query(
310+
user_id: str,
311+
dataset_id: str,
312+
product_id: str,
313+
query: GeoQuery,
314+
):
315+
"""Realize the logic for the endpoint:
316+
317+
`POST /datasets/{dataset_id}/{product_id}/execute`
318+
319+
Query the data and return the result of the request.
320+
321+
Parameters
322+
----------
323+
user_id : str
324+
ID of the user executing the query
325+
dataset_id : str
326+
ID of the dataset
327+
product_id : str
328+
ID of the product
329+
query : GeoQuery
330+
Query to perform
331+
332+
Returns
333+
-------
334+
request_id : int
335+
ID of the request
336+
337+
Raises
338+
-------
339+
MaximumAllowedSizeExceededError
340+
if the allowed size is below the estimated one
341+
EmptyDatasetError
342+
if estimated size is zero
343+
344+
"""
345+
346+
import time
347+
request_id = async_query(user_id, dataset_id, product_id, query)
348+
status, _ = DBManager().get_request_status_and_reason(request_id)
349+
log.debug("sync query: status: %s", status)
350+
while status in (RequestStatus.RUNNING, RequestStatus.QUEUED,
351+
RequestStatus.PENDING):
352+
time.sleep(1)
353+
status, _ = DBManager().get_request_status_and_reason(request_id)
354+
log.debug("sync query: status: %s", status)
355+
356+
if status is RequestStatus.DONE:
357+
download_details = DBManager().get_download_details_for_request_id(
358+
request_id
359+
)
360+
return FileResponse(
361+
path=download_details.location_path,
362+
filename=download_details.location_path.split(os.sep)[-1],
363+
)
364+
raise exc.ProductRetrievingError(
365+
dataset_id=dataset_id,
366+
product_id=product_id,
367+
status=status.name)
368+
298369

299370
@log_execution_time(log)
300371
def run_workflow(

api/app/endpoint_handlers/request.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ def get_request_resulting_size(request_id: int):
8686
If the request was not found
8787
"""
8888
if request := DBManager().get_request_details(request_id):
89-
return request.download.size_bytes
89+
size = request.download.size_bytes
90+
if not size or size == 0:
91+
raise exc.EmptyDatasetError(dataset_id=request.dataset,
92+
product_id=request.product)
93+
return size
9094
log.info(
9195
"request with id '%s' could not be found",
9296
request_id,

api/app/exceptions.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,16 @@ def __init__(self, dataset_id, product_id):
180180
product_id=product_id,
181181
)
182182
super().__init__(self.msg)
183+
184+
class ProductRetrievingError(BaseDDSException):
185+
"""Retrieving of the product failed."""
186+
187+
msg: str = "Retrieving of the product '{dataset_id}.{product_id}' failed with the status {status}"
188+
189+
def __init__(self, dataset_id, product_id, status):
190+
self.msg = self.msg.format(
191+
dataset_id=dataset_id,
192+
product_id=product_id,
193+
status=status
194+
)
195+
super().__init__(self.msg)

0 commit comments

Comments
 (0)