Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
increase version
extends opentelemetry instrumentation

properly threat mongo db errors

refactors environment summary serialization

Minor refactoring
- Enhances error handling and logging
- Fine tune hybrid locks on main repository initialization and finalization

refactor repositories accesses

fine tunes db config

turn off db connection close

fixes repo name

fixes get environment call on flight route
  • Loading branch information
GabrielBarberini committed Sep 11, 2024
commit 2821c8b94cb3d99cd748ae3dae07198345ae8b6d
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ RUN apt-get update && \

COPY ./lib /app/lib

CMD ["gunicorn", "-c", "lib/settings/gunicorn.py", "-w", "1", "--threads=2", "-k", "uvicorn.workers.UvicornWorker", "lib.api:app", "--log-level", "Debug", "-b", "0.0.0.0:3000", "--timeout", "30"]
CMD ["gunicorn", "-c", "lib/settings/gunicorn.py", "-w", "1", "--threads=2", "-k", "uvicorn.workers.UvicornWorker", "lib.api:app", "--log-level", "Debug", "-b", "0.0.0.0:3000", "--timeout", "35"]
3 changes: 3 additions & 0 deletions lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ def parse_error(error):
exc_type = type(error).__name__
exc_obj = f"{error}".replace("\n", " ").replace(" ", " ")
return f"{exc_type} exception: {exc_obj}"


from lib.api import app
8 changes: 7 additions & 1 deletion lib/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
from fastapi.openapi.utils import get_openapi
from fastapi.responses import RedirectResponse, JSONResponse

from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor

from lib import logger, parse_error
from lib.routes import flight, environment, motor, rocket

Expand All @@ -30,6 +33,9 @@
app.include_router(motor.router)
app.include_router(rocket.router)

FastAPIInstrumentor.instrument_app(app)
RequestsInstrumentor().instrument()

# Compress responses above 1KB
app.add_middleware(GZipMiddleware, minimum_size=1000)

Expand All @@ -39,7 +45,7 @@ def custom_openapi():
return app.openapi_schema
openapi_schema = get_openapi(
title="RocketPy Infinity-API",
version="1.2.0 BETA",
version="1.2.2 BETA",
description=(
"<p style='font-size: 18px;'>RocketPy Infinity-API is a RESTful Open API for RocketPy, a rocket flight simulator.</p>"
"<br/>"
Expand Down
83 changes: 47 additions & 36 deletions lib/controllers/environment.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
from typing import Union

import jsonpickle
from rocketpy.environment.environment import Environment as RocketPyEnvironment
from fastapi import HTTPException, status
from pymongo.errors import PyMongoError

from lib import logger, parse_error
from lib.models.environment import Env
from lib.services.environment import EnvironmentService
from lib.repositories.environment import EnvRepository
from lib.views.environment import (
EnvSummary,
EnvData,
EnvPlots,
EnvCreated,
EnvDeleted,
EnvUpdated,
Expand All @@ -26,7 +25,7 @@ class EnvController:
env: models.Env

Enables:
- Simulation of RocketPyEnvironment from models.Env
- Simulation of a RocketPy Environment from models.Env
- CRUD operations over models.Env on the database
"""

Expand All @@ -41,25 +40,6 @@ def env(self) -> Env:
def env(self, env: Env):
self._env = env

@staticmethod
def get_rocketpy_env(env: Env) -> RocketPyEnvironment:
"""
Get the rocketpy env object.

Returns:
RocketPyEnvironment
"""
rocketpy_env = RocketPyEnvironment(
latitude=env.latitude,
longitude=env.longitude,
elevation=env.elevation,
date=env.date,
)
rocketpy_env.set_atmospheric_model(
type=env.atmospheric_model_type, file=env.atmospheric_model_file
)
return rocketpy_env

async def create_env(self) -> Union[EnvCreated, HTTPException]:
"""
Create a env in the database.
Expand All @@ -71,6 +51,16 @@ async def create_env(self) -> Union[EnvCreated, HTTPException]:
async with EnvRepository() as env_repo:
env_repo.fetch_env(self.env)
await env_repo.create_env()
except PyMongoError as e:
logger.error(
f"controllers.environment.create_env: PyMongoError {e}"
)
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to create environment in db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
exc_str = parse_error(e)
logger.error(f"controllers.environment.create_env: {exc_str}")
Expand Down Expand Up @@ -103,6 +93,16 @@ async def get_env_by_id(env_id: str) -> Union[Env, HTTPException]:
async with EnvRepository() as env_repo:
await env_repo.get_env_by_id(env_id)
read_env = env_repo.env
except PyMongoError as e:
logger.error(
f"controllers.environment.get_env_by_id: PyMongoError {e}"
)
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to read environment from db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
exc_str = parse_error(e)
logger.error(f"controllers.environment.get_env_by_id: {exc_str}")
Expand Down Expand Up @@ -141,7 +141,7 @@ async def get_rocketpy_env_as_jsonpickle(
"""
try:
read_env = await cls.get_env_by_id(env_id)
rocketpy_env = cls.get_rocketpy_env(read_env)
rocketpy_env = EnvironmentService.from_env_model(read_env)
except HTTPException as e:
raise e from e
except Exception as e:
Expand Down Expand Up @@ -182,6 +182,16 @@ async def update_env_by_id(
env_repo.fetch_env(self.env)
await env_repo.create_env()
await env_repo.delete_env_by_id(env_id)
except PyMongoError as e:
logger.error(
f"controllers.environment.update_env: PyMongoError {e}"
)
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to update environment from db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
exc_str = parse_error(e)
logger.error(f"controllers.environment.update_env: {exc_str}")
Expand Down Expand Up @@ -215,6 +225,16 @@ async def delete_env_by_id(
try:
async with EnvRepository() as env_repo:
await env_repo.delete_env_by_id(env_id)
except PyMongoError as e:
logger.error(
f"controllers.environment.delete_env: PyMongoError {e}"
)
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to delete environment from db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
exc_str = parse_error(e)
logger.error(f"controllers.environment.delete_env: {exc_str}")
Expand All @@ -240,24 +260,15 @@ async def simulate_env(
env_id: str.

Returns:
views.EnvSummary
EnvSummary

Raises:
HTTP 404 Not Found: If the env does not exist in the database.
"""
try:
read_env = await cls.get_env_by_id(env_id)
rocketpy_env = cls.get_rocketpy_env(read_env)

env_simulation_numbers = EnvData.parse_obj(
rocketpy_env.all_info_returned()
)
env_simulation_plots = EnvPlots.parse_obj(
rocketpy_env.all_plot_info_returned()
)
env_summary = EnvSummary(
env_data=env_simulation_numbers, env_plots=env_simulation_plots
)
rocketpy_env = EnvironmentService.from_env_model(read_env)
env_summary = rocketpy_env.get_env_summary()
except HTTPException as e:
raise e from e
except Exception as e:
Expand Down
54 changes: 53 additions & 1 deletion lib/controllers/flight.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Union
from fastapi import HTTPException, status
from pymongo.errors import PyMongoError

from rocketpy.simulation.flight import Flight as RocketPyFlight

Expand Down Expand Up @@ -31,6 +32,7 @@
from lib.repositories.flight import FlightRepository
from lib.controllers.environment import EnvController
from lib.controllers.rocket import RocketController
from lib.services.environment import EnvironmentService


class FlightController:
Expand Down Expand Up @@ -87,7 +89,7 @@ def get_rocketpy_flight(flight: Flight) -> RocketPyFlight:
RocketPyFlight
"""
rocketpy_rocket = RocketController.get_rocketpy_rocket(flight.rocket)
rocketpy_env = EnvController.get_rocketpy_env(flight.environment)
rocketpy_env = EnvironmentService.from_env_model(flight.environment)
rocketpy_flight = RocketPyFlight(
rocket=rocketpy_rocket,
inclination=flight.inclination,
Expand All @@ -111,6 +113,14 @@ async def create_flight(self) -> Union[FlightCreated, HTTPException]:
motor_kind=self.motor_kind,
rocket_option=self.rocket_option,
)
except PyMongoError as e:
logger.error(f"controllers.flight.create_flight: PyMongoError {e}")
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to create flight in db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
exc_str = parse_error(e)
logger.error(f"controllers.flight.create_flight: {exc_str}")
Expand Down Expand Up @@ -143,6 +153,16 @@ async def get_flight_by_id(flight_id: str) -> Union[Flight, HTTPException]:
async with FlightRepository() as flight_repo:
await flight_repo.get_flight_by_id(flight_id)
read_flight = flight_repo.flight
except PyMongoError as e:
logger.error(
f"controllers.flight.get_flight_by_id: PyMongoError {e}"
)
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to read flight from db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
exc_str = parse_error(e)
logger.error(f"controllers.flight.get_flight_by_id: {exc_str}")
Expand Down Expand Up @@ -225,6 +245,14 @@ async def update_flight_by_id(
rocket_option=self.rocket_option,
)
await flight_repo.delete_flight_by_id(flight_id)
except PyMongoError as e:
logger.error(f"controllers.flight.update_flight: PyMongoError {e}")
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to update flight in db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
exc_str = parse_error(e)
logger.error(f"controllers.flight.update_flight: {exc_str}")
Expand Down Expand Up @@ -268,6 +296,14 @@ async def update_env_by_flight_id(
rocket_option=read_flight.rocket.rocket_option,
)
await flight_repo.delete_flight_by_id(flight_id)
except PyMongoError as e:
logger.error(
f"controllers.flight.update_env_by_flight_id: PyMongoError {e}"
)
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to update environment from db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
Expand Down Expand Up @@ -315,6 +351,14 @@ async def update_rocket_by_flight_id(
motor_kind=motor_kind, rocket_option=rocket_option
)
await flight_repo.delete_flight_by_id(flight_id)
except PyMongoError as e:
logger.error(
f"controllers.flight.update_rocket_by_flight_id: PyMongoError {e}"
)
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to update rocket from db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
Expand Down Expand Up @@ -350,6 +394,14 @@ async def delete_flight_by_id(
try:
async with FlightRepository() as flight_repo:
await flight_repo.delete_flight_by_id(flight_id)
except PyMongoError as e:
logger.error(f"controllers.flight.delete_flight: PyMongoError {e}")
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to delete flight from db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
exc_str = parse_error(e)
logger.error(f"controllers.flight.delete_flight: {exc_str}")
Expand Down
35 changes: 35 additions & 0 deletions lib/controllers/motor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Union
from fastapi import HTTPException, status
from pymongo.errors import PyMongoError
from rocketpy.motors.solid_motor import SolidMotor
from rocketpy.motors.liquid_motor import LiquidMotor
from rocketpy.motors.hybrid_motor import HybridMotor
Expand Down Expand Up @@ -119,6 +120,14 @@ async def create_motor(self) -> Union[MotorCreated, HTTPException]:
async with MotorRepository() as motor_repo:
motor_repo.fetch_motor(self.motor)
await motor_repo.create_motor(motor_kind=self.motor_kind)
except PyMongoError as e:
logger.error(f"controllers.motor.create_motor: PyMongoError {e}")
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to create motor in db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
exc_str = parse_error(e)
logger.error(f"controllers.motor.create_motor: {exc_str}")
Expand Down Expand Up @@ -151,6 +160,16 @@ async def get_motor_by_id(motor_id: str) -> Union[Motor, HTTPException]:
async with MotorRepository() as motor_repo:
await motor_repo.get_motor_by_id(motor_id)
read_motor = motor_repo.motor
except PyMongoError as e:
logger.error(
f"controllers.motor.get_motor_by_id: PyMongoError {e}"
)
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to read motor from db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
exc_str = parse_error(e)
logger.error(f"controllers.motor.get_motor_by_id: {exc_str}")
Expand Down Expand Up @@ -230,6 +249,14 @@ async def update_motor_by_id(
motor_repo.fetch_motor(self.motor)
await motor_repo.create_motor(motor_kind=self.motor_kind)
await motor_repo.delete_motor_by_id(motor_id)
except PyMongoError as e:
logger.error(f"controllers.motor.update_motor: PyMongoError {e}")
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to update motor in db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
exc_str = parse_error(e)
logger.error(f"controllers.motor.update_motor: {exc_str}")
Expand Down Expand Up @@ -263,6 +290,14 @@ async def delete_motor_by_id(
try:
async with MotorRepository() as motor_repo:
await motor_repo.delete_motor_by_id(motor_id)
except PyMongoError as e:
logger.error(f"controllers.motor.delete_motor: PyMongoError {e}")
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Failed to delete motor from db",
) from e
except HTTPException as e:
raise e from e
except Exception as e:
exc_str = parse_error(e)
logger.error(f"controllers.motor.delete_motor: {exc_str}")
Expand Down
Loading