diff --git a/api/app/v1/endpoints/read/commit.py b/api/app/v1/endpoints/read/commit.py index bd9b594..2cd404e 100644 --- a/api/app/v1/endpoints/read/commit.py +++ b/api/app/v1/endpoints/read/commit.py @@ -13,7 +13,9 @@ # limitations under the License. import json +import logging +import asyncpg from app import ANONYMOUS_VIEWER, AUTHORIZATION, REDIS from app.db.asyncpg_db import get_pool from app.db.redis_db import redis @@ -24,6 +26,8 @@ from .query_parameters import CommonQueryParams, get_common_query_params from .read import asyncpg_stream_results, wrapped_result_generator +logger = logging.getLogger(__name__) + v1 = APIRouter() user = Header(default=None, include_in_schema=False) @@ -97,7 +101,7 @@ async def get_commits( media_type="application/json", status_code=status.HTTP_200_OK, ) - except Exception as e: + except StopAsyncIteration: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content={ @@ -106,6 +110,29 @@ async def get_commits( "message": "Not Found", }, ) + except ( + asyncpg.PostgresConnectionError, + asyncpg.TooManyConnectionsError, + ): + logger.exception("Database unavailable in get_commits") + return JSONResponse( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + content={ + "code": 503, + "type": "error", + "message": "Database temporarily unavailable", + }, + ) + except Exception: + logger.exception("Unexpected streaming error in get_commits") + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={ + "code": 500, + "type": "error", + "message": "Internal server error", + }, + ) except Exception as e: return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/api/app/v1/endpoints/read/datastream.py b/api/app/v1/endpoints/read/datastream.py index ac9b253..358c5da 100644 --- a/api/app/v1/endpoints/read/datastream.py +++ b/api/app/v1/endpoints/read/datastream.py @@ -13,7 +13,9 @@ # limitations under the License. import json +import logging +import asyncpg from app import ANONYMOUS_VIEWER, AUTHORIZATION, REDIS from app.db.asyncpg_db import get_pool from app.db.redis_db import redis @@ -24,6 +26,8 @@ from .query_parameters import CommonQueryParams, get_common_query_params from .read import asyncpg_stream_results, wrapped_result_generator +logger = logging.getLogger(__name__) + v1 = APIRouter() user = Header(default=None, include_in_schema=False) @@ -96,7 +100,7 @@ async def get_datastreams( media_type="application/json", status_code=status.HTTP_200_OK, ) - except Exception as e: + except StopAsyncIteration: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content={ @@ -105,6 +109,29 @@ async def get_datastreams( "message": "Not Found", }, ) + except ( + asyncpg.PostgresConnectionError, + asyncpg.TooManyConnectionsError, + ): + logger.exception("Database unavailable in get_datastreams") + return JSONResponse( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + content={ + "code": 503, + "type": "error", + "message": "Database temporarily unavailable", + }, + ) + except Exception: + logger.exception("Unexpected streaming error in get_datastreams") + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={ + "code": 500, + "type": "error", + "message": "Internal server error", + }, + ) except Exception as e: return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/api/app/v1/endpoints/read/feature_of_interest.py b/api/app/v1/endpoints/read/feature_of_interest.py index cc14f9a..8dab2fe 100644 --- a/api/app/v1/endpoints/read/feature_of_interest.py +++ b/api/app/v1/endpoints/read/feature_of_interest.py @@ -13,7 +13,9 @@ # limitations under the License. import json +import logging +import asyncpg from app import ANONYMOUS_VIEWER, AUTHORIZATION, REDIS from app.db.asyncpg_db import get_pool from app.db.redis_db import redis @@ -24,6 +26,8 @@ from .query_parameters import CommonQueryParams, get_common_query_params from .read import asyncpg_stream_results, wrapped_result_generator +logger = logging.getLogger(__name__) + v1 = APIRouter() user = Header(default=None, include_in_schema=False) @@ -96,7 +100,7 @@ async def get_features_of_interest( media_type="application/json", status_code=status.HTTP_200_OK, ) - except Exception as e: + except StopAsyncIteration: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content={ @@ -105,6 +109,29 @@ async def get_features_of_interest( "message": "Not Found", }, ) + except ( + asyncpg.PostgresConnectionError, + asyncpg.TooManyConnectionsError, + ): + logger.exception("Database unavailable in get_features_of_interest") + return JSONResponse( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + content={ + "code": 503, + "type": "error", + "message": "Database temporarily unavailable", + }, + ) + except Exception: + logger.exception("Unexpected streaming error in get_features_of_interest") + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={ + "code": 500, + "type": "error", + "message": "Internal server error", + }, + ) except Exception as e: return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/api/app/v1/endpoints/read/historical_location.py b/api/app/v1/endpoints/read/historical_location.py index aac2c45..8c8377e 100644 --- a/api/app/v1/endpoints/read/historical_location.py +++ b/api/app/v1/endpoints/read/historical_location.py @@ -13,7 +13,9 @@ # limitations under the License. import json +import logging +import asyncpg from app import ANONYMOUS_VIEWER, AUTHORIZATION, REDIS from app.db.asyncpg_db import get_pool from app.db.redis_db import redis @@ -24,6 +26,8 @@ from .query_parameters import CommonQueryParams, get_common_query_params from .read import asyncpg_stream_results, wrapped_result_generator +logger = logging.getLogger(__name__) + v1 = APIRouter() user = Header(default=None, include_in_schema=False) @@ -96,7 +100,7 @@ async def get_historical_locations( media_type="application/json", status_code=status.HTTP_200_OK, ) - except Exception as e: + except StopAsyncIteration: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content={ @@ -105,6 +109,29 @@ async def get_historical_locations( "message": "Not Found", }, ) + except ( + asyncpg.PostgresConnectionError, + asyncpg.TooManyConnectionsError, + ): + logger.exception("Database unavailable in get_historical_locations") + return JSONResponse( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + content={ + "code": 503, + "type": "error", + "message": "Database temporarily unavailable", + }, + ) + except Exception: + logger.exception("Unexpected streaming error in get_historical_locations") + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={ + "code": 500, + "type": "error", + "message": "Internal server error", + }, + ) except Exception as e: return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/api/app/v1/endpoints/read/location.py b/api/app/v1/endpoints/read/location.py index 7be3e32..ece99b2 100644 --- a/api/app/v1/endpoints/read/location.py +++ b/api/app/v1/endpoints/read/location.py @@ -13,7 +13,9 @@ # limitations under the License. import json +import logging +import asyncpg from app import ANONYMOUS_VIEWER, AUTHORIZATION, REDIS from app.db.asyncpg_db import get_pool from app.db.redis_db import redis @@ -24,6 +26,8 @@ from .query_parameters import CommonQueryParams, get_common_query_params from .read import asyncpg_stream_results, wrapped_result_generator +logger = logging.getLogger(__name__) + v1 = APIRouter() user = Header(default=None, include_in_schema=False) @@ -96,7 +100,7 @@ async def get_locations( media_type="application/json", status_code=status.HTTP_200_OK, ) - except Exception as e: + except StopAsyncIteration: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content={ @@ -105,6 +109,29 @@ async def get_locations( "message": "Not Found", }, ) + except ( + asyncpg.PostgresConnectionError, + asyncpg.TooManyConnectionsError, + ): + logger.exception("Database unavailable in get_locations") + return JSONResponse( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + content={ + "code": 503, + "type": "error", + "message": "Database temporarily unavailable", + }, + ) + except Exception: + logger.exception("Unexpected streaming error in get_locations") + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={ + "code": 500, + "type": "error", + "message": "Internal server error", + }, + ) except Exception as e: return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/api/app/v1/endpoints/read/network.py b/api/app/v1/endpoints/read/network.py index ed688da..cf65148 100644 --- a/api/app/v1/endpoints/read/network.py +++ b/api/app/v1/endpoints/read/network.py @@ -13,7 +13,9 @@ # limitations under the License. import json +import logging +import asyncpg from app import ANONYMOUS_VIEWER, AUTHORIZATION, REDIS from app.db.asyncpg_db import get_pool from app.db.redis_db import redis @@ -24,6 +26,8 @@ from .query_parameters import CommonQueryParams, get_common_query_params from .read import asyncpg_stream_results, wrapped_result_generator +logger = logging.getLogger(__name__) + v1 = APIRouter() user = Header(default=None, include_in_schema=False) @@ -96,7 +100,7 @@ async def get_networks( media_type="application/json", status_code=status.HTTP_200_OK, ) - except Exception as e: + except StopAsyncIteration: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content={ @@ -105,6 +109,29 @@ async def get_networks( "message": "Not Found", }, ) + except ( + asyncpg.PostgresConnectionError, + asyncpg.TooManyConnectionsError, + ): + logger.exception("Database unavailable in get_networks") + return JSONResponse( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + content={ + "code": 503, + "type": "error", + "message": "Database temporarily unavailable", + }, + ) + except Exception: + logger.exception("Unexpected streaming error in get_networks") + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={ + "code": 500, + "type": "error", + "message": "Internal server error", + }, + ) except Exception as e: return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/api/app/v1/endpoints/read/observation.py b/api/app/v1/endpoints/read/observation.py index f28aabe..a510853 100644 --- a/api/app/v1/endpoints/read/observation.py +++ b/api/app/v1/endpoints/read/observation.py @@ -13,7 +13,9 @@ # limitations under the License. import json +import logging +import asyncpg from app import ANONYMOUS_VIEWER, AUTHORIZATION, REDIS from app.db.asyncpg_db import get_pool from app.db.redis_db import redis @@ -24,6 +26,8 @@ from .query_parameters import CommonQueryParams, get_common_query_params from .read import asyncpg_stream_results, wrapped_result_generator +logger = logging.getLogger(__name__) + v1 = APIRouter() user = Header(default=None, include_in_schema=False) @@ -96,7 +100,7 @@ async def get_observations( media_type="application/json", status_code=status.HTTP_200_OK, ) - except Exception as e: + except StopAsyncIteration: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content={ @@ -105,6 +109,29 @@ async def get_observations( "message": "Not Found", }, ) + except ( + asyncpg.PostgresConnectionError, + asyncpg.TooManyConnectionsError, + ): + logger.exception("Database unavailable in get_observations") + return JSONResponse( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + content={ + "code": 503, + "type": "error", + "message": "Database temporarily unavailable", + }, + ) + except Exception: + logger.exception("Unexpected streaming error in get_observations") + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={ + "code": 500, + "type": "error", + "message": "Internal server error", + }, + ) except Exception as e: return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/api/app/v1/endpoints/read/observed_property.py b/api/app/v1/endpoints/read/observed_property.py index 5f6ee00..488f966 100644 --- a/api/app/v1/endpoints/read/observed_property.py +++ b/api/app/v1/endpoints/read/observed_property.py @@ -13,7 +13,9 @@ # limitations under the License. import json +import logging +import asyncpg from app import ANONYMOUS_VIEWER, AUTHORIZATION, REDIS from app.db.asyncpg_db import get_pool from app.db.redis_db import redis @@ -24,6 +26,8 @@ from .query_parameters import CommonQueryParams, get_common_query_params from .read import asyncpg_stream_results, wrapped_result_generator +logger = logging.getLogger(__name__) + v1 = APIRouter() user = Header(default=None, include_in_schema=False) @@ -96,7 +100,7 @@ async def get_observed_properties( media_type="application/json", status_code=status.HTTP_200_OK, ) - except Exception as e: + except StopAsyncIteration: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content={ @@ -105,6 +109,29 @@ async def get_observed_properties( "message": "Not Found", }, ) + except ( + asyncpg.PostgresConnectionError, + asyncpg.TooManyConnectionsError, + ): + logger.exception("Database unavailable in get_observed_properties") + return JSONResponse( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + content={ + "code": 503, + "type": "error", + "message": "Database temporarily unavailable", + }, + ) + except Exception: + logger.exception("Unexpected streaming error in get_observed_properties") + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={ + "code": 500, + "type": "error", + "message": "Internal server error", + }, + ) except Exception as e: return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/api/app/v1/endpoints/read/sensor.py b/api/app/v1/endpoints/read/sensor.py index 79639e8..ba018fb 100644 --- a/api/app/v1/endpoints/read/sensor.py +++ b/api/app/v1/endpoints/read/sensor.py @@ -13,7 +13,9 @@ # limitations under the License. import json +import logging +import asyncpg from app import ANONYMOUS_VIEWER, AUTHORIZATION, REDIS from app.db.asyncpg_db import get_pool from app.db.redis_db import redis @@ -24,6 +26,8 @@ from .query_parameters import CommonQueryParams, get_common_query_params from .read import asyncpg_stream_results, wrapped_result_generator +logger = logging.getLogger(__name__) + v1 = APIRouter() user = Header(default=None, include_in_schema=False) @@ -96,7 +100,7 @@ async def get_sensors( media_type="application/json", status_code=status.HTTP_200_OK, ) - except Exception as e: + except StopAsyncIteration: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content={ @@ -105,6 +109,29 @@ async def get_sensors( "message": "Not Found", }, ) + except ( + asyncpg.PostgresConnectionError, + asyncpg.TooManyConnectionsError, + ): + logger.exception("Database unavailable in get_sensors") + return JSONResponse( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + content={ + "code": 503, + "type": "error", + "message": "Database temporarily unavailable", + }, + ) + except Exception: + logger.exception("Unexpected streaming error in get_sensors") + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={ + "code": 500, + "type": "error", + "message": "Internal server error", + }, + ) except Exception as e: return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/api/app/v1/endpoints/read/thing.py b/api/app/v1/endpoints/read/thing.py index 29071b4..67b133b 100644 --- a/api/app/v1/endpoints/read/thing.py +++ b/api/app/v1/endpoints/read/thing.py @@ -13,7 +13,9 @@ # limitations under the License. import json +import logging +import asyncpg from app import ANONYMOUS_VIEWER, AUTHORIZATION, REDIS from app.db.asyncpg_db import get_pool from app.db.redis_db import redis @@ -24,6 +26,8 @@ from .query_parameters import CommonQueryParams, get_common_query_params from .read import asyncpg_stream_results, wrapped_result_generator +logger = logging.getLogger(__name__) + v1 = APIRouter() user = Header(default=None, include_in_schema=False) @@ -96,7 +100,7 @@ async def get_things( media_type="application/json", status_code=status.HTTP_200_OK, ) - except Exception as e: + except StopAsyncIteration: return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, content={ @@ -105,6 +109,29 @@ async def get_things( "message": "Not Found", }, ) + except ( + asyncpg.PostgresConnectionError, + asyncpg.TooManyConnectionsError, + ): + logger.exception("Database unavailable in get_things") + return JSONResponse( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + content={ + "code": 503, + "type": "error", + "message": "Database temporarily unavailable", + }, + ) + except Exception: + logger.exception("Unexpected streaming error in get_things") + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={ + "code": 500, + "type": "error", + "message": "Internal server error", + }, + ) except Exception as e: return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST,