Skip to content

Commit

Permalink
editoast: app health and layers refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Wadjetz committed Jul 9, 2024
1 parent ec8e87e commit d59cddf
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 35 deletions.
11 changes: 9 additions & 2 deletions editoast/editoast_models/src/db_connection_pool.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
use std::sync::Arc;

use diesel::sql_query;
use diesel::ConnectionError;
use diesel::ConnectionResult;
use diesel_async::pooled_connection::deadpool::Object;
use diesel_async::pooled_connection::deadpool::Pool;

use diesel_async::pooled_connection::AsyncDieselConnectionManager;
use diesel_async::pooled_connection::ManagerConfig;
use diesel_async::AsyncPgConnection;
use diesel_async::RunQueryDsl;
use futures::future::BoxFuture;
use futures::Future;
use futures_util::FutureExt as _;
use openssl::ssl::SslConnector;
use openssl::ssl::SslMethod;
use openssl::ssl::SslVerifyMode;
use std::sync::Arc;
use url::Url;

#[cfg(feature = "testing")]
Expand Down Expand Up @@ -320,6 +322,11 @@ impl DbConnectionPoolV2 {
}
}

pub async fn ping_database(conn: &mut DbConnection) -> Result<(), EditoastModelsError> {
sql_query("SELECT 1").execute(conn).await?;
Ok(())
}

pub fn create_connection_pool(
url: Url,
max_size: usize,
Expand Down
1 change: 1 addition & 0 deletions editoast/editoast_models/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod db_connection_pool;
mod error;

pub use db_connection_pool::create_connection_pool;
pub use db_connection_pool::ping_database;
pub use db_connection_pool::DbConnectionPoolV2;
pub use error::EditoastModelsError;

Expand Down
20 changes: 20 additions & 0 deletions editoast/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3794,6 +3794,25 @@ components:
enum:
- STANDARD
- MARECO
EditoastAppHealthErrorTimeoutError:
type: object
required:
- type
- status
- message
properties:
context:
type: object
message:
type: string
status:
type: integer
enum:
- 400
type:
type: string
enum:
- editoast:app_health_error:TimeoutError
EditoastAttachedErrorTrackNotFound:
type: object
required:
Expand Down Expand Up @@ -4248,6 +4267,7 @@ components:
- editoast:electrical_profiles:NotFound
EditoastError:
oneOf:
- $ref: '#/components/schemas/EditoastAppHealthErrorTimeoutError'
- $ref: '#/components/schemas/EditoastAttachedErrorTrackNotFound'
- $ref: '#/components/schemas/EditoastAutoFixesEditoastErrorConflictingFixesOnSameObject'
- $ref: '#/components/schemas/EditoastAutoFixesEditoastErrorFixTrialFailure'
Expand Down
1 change: 1 addition & 0 deletions editoast/src/models/layers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod geo_json_and_data;
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
use diesel::sql_query;
use diesel::sql_types::Integer;
use diesel::sql_types::Jsonb;
use diesel::sql_types::Text;
use diesel_async::RunQueryDsl;
use editoast_models::DbConnection;
use editoast_models::EditoastModelsError;
use geos::geojson::Geometry;
use geos::geojson::Value as GeoJsonValue;
use mvt::Feature;
Expand All @@ -11,6 +16,7 @@ use serde::Deserialize;
use serde::Serialize;
use serde_json::Value as JsonValue;

use crate::map::Layer;
use crate::map::View;

#[derive(Clone, QueryableByName, Queryable, Debug, Serialize, Deserialize)]
Expand All @@ -21,17 +27,39 @@ pub struct GeoJsonAndData {
pub data: JsonValue,
}

fn geometry_into_mvt_geom_type(geometry: &Geometry) -> GeomType {
match geometry.value {
GeoJsonValue::Point { .. } => GeomType::Point,
GeoJsonValue::MultiPoint { .. } => GeomType::Point,
GeoJsonValue::LineString { .. } => GeomType::Linestring,
GeoJsonValue::MultiLineString { .. } => GeomType::Linestring,
_ => panic!("geometry type unsupported by editoast tiling system"),
#[derive(Debug)]
pub struct GeoPoint {
x: u64,
y: u64,
z: u64,
}

impl GeoPoint {
pub fn new(x: u64, y: u64, z: u64) -> Self {
Self { x, y, z }
}
}

impl GeoJsonAndData {
pub async fn get_records(
conn: &mut DbConnection,
layer: &Layer,
view: &View,
infra: i64,
geo_point: &GeoPoint,
) -> Result<Vec<GeoJsonAndData>, EditoastModelsError> {
let geo_json_query = get_geo_json_sql_query(&layer.table_name, view);
let records = sql_query(geo_json_query)
.bind::<Integer, _>(geo_point.z as i32)
.bind::<Integer, _>(geo_point.x as i32)
.bind::<Integer, _>(geo_point.y as i32)
.bind::<Integer, _>(infra as i32)
.get_results::<GeoJsonAndData>(conn)
.await?;

Ok(records)
}

/// Converts GeoJsonAndData as mvt GeomData
pub fn as_geom_data(&self) -> GeomData {
let geo_json = serde_json::from_str::<Geometry>(&self.geo_json).unwrap();
Expand Down Expand Up @@ -65,6 +93,16 @@ impl GeoJsonAndData {
}
}

fn geometry_into_mvt_geom_type(geometry: &Geometry) -> GeomType {
match geometry.value {
GeoJsonValue::Point { .. } => GeomType::Point,
GeoJsonValue::MultiPoint { .. } => GeomType::Point,
GeoJsonValue::LineString { .. } => GeomType::Linestring,
GeoJsonValue::MultiLineString { .. } => GeomType::Linestring,
_ => panic!("geometry type unsupported by editoast tiling system"),
}
}

/// Adds tags to an MVT feature
///
/// tags must be flattened as mvt tags are only one level depth
Expand Down
1 change: 1 addition & 0 deletions editoast/src/models/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod layers;
pub mod pathfinding;
mod scenario;
mod text_array;
Expand Down
25 changes: 7 additions & 18 deletions editoast/src/views/layers/mod.rs → editoast/src/views/layers.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
mod mvt_utils;

use std::collections::HashMap;

use actix_web::get;
Expand All @@ -8,13 +6,8 @@ use actix_web::web::Json;
use actix_web::web::Path;
use actix_web::web::Query;
use actix_web::HttpResponse;
use diesel::sql_query;
use diesel::sql_types::Integer;
use diesel_async::RunQueryDsl;
use editoast_derive::EditoastError;
use mvt_utils::create_and_fill_mvt_tile;
use mvt_utils::get_geo_json_sql_query;
use mvt_utils::GeoJsonAndData;
use editoast_models::DbConnectionPoolV2;
use redis::AsyncCommands;
use serde::Deserialize;
use serde::Serialize;
Expand All @@ -30,8 +23,10 @@ use crate::map::get_view_cache_prefix;
use crate::map::Layer;
use crate::map::MapLayers;
use crate::map::Tile;
use crate::models::layers::geo_json_and_data::create_and_fill_mvt_tile;
use crate::models::layers::geo_json_and_data::GeoJsonAndData;
use crate::models::layers::geo_json_and_data::GeoPoint;
use crate::RedisClient;
use editoast_models::DbConnectionPoolV2;

crate::routes! {
"/layers" => {
Expand Down Expand Up @@ -208,15 +203,9 @@ async fn cache_and_get_mvt_tile(
.body(value));
}

let geo_json_query = get_geo_json_sql_query(&layer.table_name, view);
let mut conn = db_pool.get().await?;
let records = sql_query(geo_json_query)
.bind::<Integer, _>(z as i32)
.bind::<Integer, _>(x as i32)
.bind::<Integer, _>(y as i32)
.bind::<Integer, _>(infra as i32)
.get_results::<GeoJsonAndData>(&mut conn)
.await?;
let conn = &mut db_pool.get().await?;
let records =
GeoJsonAndData::get_records(conn, layer, view, infra, &GeoPoint::new(z, x, y)).await?;

let mvt_bytes: Vec<u8> = create_and_fill_mvt_tile(layer_slug, records)
.to_bytes()
Expand Down
45 changes: 37 additions & 8 deletions editoast/src/views/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,22 @@ pub mod work_schedules;
mod test_app;

use std::ops::DerefMut as _;
use std::sync::Arc;
use std::time::Duration;

pub use openapi::OpenApiRoot;

use actix_web::get;
use actix_web::web::Data;
use actix_web::web::Json;
use diesel::sql_query;
use editoast_derive::EditoastError;
use editoast_models::ping_database;
use editoast_models::DbConnectionPoolV2;
use redis::cmd;
use serde_derive::Deserialize;
use serde_derive::Serialize;
use thiserror::Error;
use tokio::time::timeout;
use utoipa::ToSchema;

use crate::client::get_app_version;
Expand All @@ -49,7 +55,6 @@ use crate::infra_cache::operation;
use crate::models;
use crate::modelsv2;
use crate::RedisClient;
use editoast_models::DbConnectionPoolV2;

crate::routes! {
(health, version, core_version),
Expand Down Expand Up @@ -95,6 +100,13 @@ editoast_common::schemas! {
work_schedules::schemas(),
}

#[derive(Debug, Error, EditoastError)]
#[editoast_error(base_id = "app_health_error")]
pub enum AppHealthError {
#[error("Timeout error")]
TimeoutError,
}

#[utoipa::path(
responses(
(status = 200, description = "Check if Editoast is running correctly", body = String)
Expand All @@ -105,14 +117,31 @@ async fn health(
db_pool: Data<DbConnectionPoolV2>,
redis_client: Data<RedisClient>,
) -> Result<&'static str> {
use diesel_async::RunQueryDsl;
sql_query("SELECT 1")
.execute(db_pool.get().await?.deref_mut())
.await?;
timeout(
Duration::from_millis(500),
check_health(db_pool.into_inner(), redis_client.into_inner()),
)
.await
.map_err(|_| AppHealthError::TimeoutError)??;
Ok("ok")
}

async fn check_health(
db_pool: Arc<DbConnectionPoolV2>,
redis_client: Arc<RedisClient>,
) -> Result<()> {
let mut db_connection = db_pool.clone().get().await?;
let (_, _) = tokio::join!(
ping_database(db_connection.deref_mut()),
ping_redis(redis_client)
);
Ok(())
}

async fn ping_redis(redis_client: Arc<RedisClient>) -> Result<()> {
let mut conn = redis_client.get_connection().await?;
cmd("PING").query_async::<_, ()>(&mut conn).await.unwrap();
Ok("ok")
cmd("PING").query_async::<_, ()>(&mut conn).await?;
Ok(())
}

#[derive(ToSchema, Serialize, Deserialize)]
Expand Down

0 comments on commit d59cddf

Please sign in to comment.