[BE] Use single connections instead of a Pool

master
Araozu 2023-12-13 09:23:39 -05:00
parent 673cd96a01
commit ad7d224207
9 changed files with 46 additions and 71 deletions

View File

@ -2,6 +2,7 @@ use log::{error, info};
use reqwest::Client; use reqwest::Client;
use rocket::http::Status; use rocket::http::Status;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use sqlx::Connection;
use crate::json_result::JsonResult; use crate::json_result::JsonResult;
use crate::model::person::{PersonCreate, PersonLink}; use crate::model::person::{PersonCreate, PersonLink};
@ -11,7 +12,7 @@ use crate::{db, model::person::Person};
#[get("/person/<dni>")] #[get("/person/<dni>")]
pub async fn get_by_dni(dni: i32) -> (Status, Json<JsonResult<Person>>) { pub async fn get_by_dni(dni: i32) -> (Status, Json<JsonResult<Person>>) {
let db = match db().await { let mut db = match db().await {
Ok(db) => db, Ok(db) => db,
Err(reason) => { Err(reason) => {
return (Status::InternalServerError, JsonResult::err(reason)); return (Status::InternalServerError, JsonResult::err(reason));

View File

@ -12,7 +12,7 @@ use std::{
// TODO: Move to ENV // TODO: Move to ENV
const SCAN_PATH: &str = "/srv/srv/shares/eegsac/ESCANEOS/"; const SCAN_PATH: &str = "/srv/srv/shares/eegsac/ESCANEOS/";
/// Represents the result of parsing a QR code, and look for an eegsac URL. /// Represents the result of parsing a QR code, and looking for an eegsac URL.
/// ///
/// When the frontend requests the list of files available for conversion, this /// When the frontend requests the list of files available for conversion, this
/// is sent. It contains essentially a unix timestamp /// is sent. It contains essentially a unix timestamp

View File

@ -1,8 +1,9 @@
use cors::Cors; use cors::Cors;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use sqlx::mysql::MySqlPoolOptions; use sqlx::mysql::MySqlPoolOptions;
use sqlx::{MySql, Pool}; use sqlx::{MySql, Pool, MySqlConnection};
use std::env; use std::env;
use sqlx::Connection;
#[macro_use] #[macro_use]
extern crate rocket; extern crate rocket;
@ -14,32 +15,12 @@ mod online_classroom;
pub mod json_result; pub mod json_result;
static DB: OnceCell<Pool<MySql>> = OnceCell::new(); /// Opens & returns a connection to the database
/// Returns a global reference to the database pool
/// ///
/// If the database pool has not been initialized, this function will attempt to initialize it /// We don't use a connection pool because it often times out,
/// up to 3 times /// we don't have a lot of traffic and reiniting the pool would
/// /// require to change a lot of code in multiple places.
/// If the database pool fails to initialize, this function will panic. pub async fn db() -> Result<MySqlConnection, String> {
pub async fn db() -> Result<&'static Pool<MySql>, String> {
let attempts = 3;
for _ in 0..attempts {
match DB.get() {
Some(db) => return Ok(db),
None => {
log::info!("DB not initialized, initializing from db()");
let _ = init_db().await;
}
}
}
log::error!("Failed to initialize DB after {} attempts", attempts);
Err("Failed to initialize DB".to_string())
}
pub async fn init_db() -> Result<(), String> {
/* /*
Init DB and set it as a global variable Init DB and set it as a global variable
*/ */
@ -48,21 +29,12 @@ pub async fn init_db() -> Result<(), String> {
Err(_) => return Err("env DATABASE_URL not found".to_string()), Err(_) => return Err("env DATABASE_URL not found".to_string()),
}; };
let pool = MySqlPoolOptions::new() let conn = sqlx::MySqlConnection::connect(db_url.as_str()).await;
.max_connections(5)
.connect(db_url.as_str())
.await;
match pool { match conn {
Ok(pool) => match DB.set(pool) { Ok(connection) => Ok(connection),
Ok(_) => Ok(()), Err(reason) => {
Err(_) => { log::error!("Error connecting to DB: {}", reason);
log::error!("Failed to set DB global variable");
Err("Failed to set DB".to_string())
}
},
Err(e) => {
log::error!("Error connecting to DB: {}", e);
Err("Error connecting to DB".to_string()) Err("Error connecting to DB".to_string())
} }
} }
@ -73,7 +45,7 @@ async fn rocket() -> _ {
dotenvy::dotenv().expect("Failed to load .env file"); dotenvy::dotenv().expect("Failed to load .env file");
env_logger::init(); env_logger::init();
init_db().await; // init_db().await;
/* Init Rocket */ /* Init Rocket */
rocket::build().attach(Cors {}).mount( rocket::build().attach(Cors {}).mount(

View File

@ -28,14 +28,14 @@ pub struct Course {
impl Course { impl Course {
pub async fn get_all() -> Result<Vec<Course>, String> { pub async fn get_all() -> Result<Vec<Course>, String> {
let db = match db().await { let mut db = match db().await {
Ok(db) => db, Ok(db) => db,
Err(reason) => { Err(reason) => {
return Err(reason); return Err(reason);
} }
}; };
let results = sqlx::query!("SELECT * FROM course").fetch_all(db).await; let results = sqlx::query!("SELECT * FROM course").fetch_all(&mut db).await;
let results = match results { let results = match results {
Ok(res) => res, Ok(res) => res,
@ -60,7 +60,7 @@ impl Course {
} }
pub async fn get_course_name(course_id: i32) -> Result<String, String> { pub async fn get_course_name(course_id: i32) -> Result<String, String> {
let db = match db().await { let mut db = match db().await {
Ok(db) => db, Ok(db) => db,
Err(reason) => { Err(reason) => {
return Err(reason); return Err(reason);
@ -71,7 +71,7 @@ impl Course {
"SELECT course_name FROM course WHERE course_id = ?", "SELECT course_name FROM course WHERE course_id = ?",
course_id course_id
) )
.fetch_one(db) .fetch_one(&mut db)
.await; .await;
match res { match res {

View File

@ -9,7 +9,7 @@ pub struct CustomLabel {
impl CustomLabel { impl CustomLabel {
pub async fn get_all() -> Result<Vec<CustomLabel>, String> { pub async fn get_all() -> Result<Vec<CustomLabel>, String> {
let db = match db().await { let mut db = match db().await {
Ok(db) => db, Ok(db) => db,
Err(reason) => return Err(reason), Err(reason) => return Err(reason),
}; };
@ -20,7 +20,7 @@ impl CustomLabel {
FROM custom_label FROM custom_label
"#, "#,
) )
.fetch_all(db) .fetch_all(&mut db)
.await; .await;
match result { match result {
@ -33,7 +33,7 @@ impl CustomLabel {
} }
pub async fn get_id_by_value(value: &String) -> Result<i32, String> { pub async fn get_id_by_value(value: &String) -> Result<i32, String> {
let db = match db().await { let mut db = match db().await {
Ok(db) => db, Ok(db) => db,
Err(reason) => return Err(reason), Err(reason) => return Err(reason),
}; };
@ -42,7 +42,7 @@ impl CustomLabel {
"SELECT custom_label_id FROM custom_label WHERE custom_label_value = ?", "SELECT custom_label_id FROM custom_label WHERE custom_label_value = ?",
value value
) )
.fetch_all(db) .fetch_all(&mut db)
.await; .await;
let result = match result { let result = match result {
@ -63,7 +63,7 @@ impl CustomLabel {
} }
pub async fn create(value: &String) -> Result<i32, String> { pub async fn create(value: &String) -> Result<i32, String> {
let db = match db().await { let mut db = match db().await {
Ok(db) => db, Ok(db) => db,
Err(reason) => return Err(reason), Err(reason) => return Err(reason),
}; };
@ -72,7 +72,7 @@ impl CustomLabel {
"INSERT INTO custom_label (custom_label_value) VALUES (?)", "INSERT INTO custom_label (custom_label_value) VALUES (?)",
value value
) )
.execute(db) .execute(&mut db)
.await; .await;
if let Err(err) = result { if let Err(err) = result {

View File

@ -34,13 +34,13 @@ pub struct Person {
impl Person { impl Person {
pub async fn get_by_dni(dni: i32) -> Result<Person, DBError> { pub async fn get_by_dni(dni: i32) -> Result<Person, DBError> {
let db = match db().await { let mut db = match db().await {
Ok(db) => db, Ok(db) => db,
Err(reason) => return Err(DBError::Str(reason)), Err(reason) => return Err(DBError::Str(reason)),
}; };
let result = sqlx::query_as!(Person, "SELECT * FROM person WHERE person_dni = ?", dni) let result = sqlx::query_as!(Person, "SELECT * FROM person WHERE person_dni = ?", dni)
.fetch_one(db) .fetch_one(&mut db)
.await; .await;
match result { match result {
@ -63,7 +63,7 @@ pub struct PersonCreate {
impl PersonCreate { impl PersonCreate {
pub async fn create(&self) -> Result<(), String> { pub async fn create(&self) -> Result<(), String> {
let db = match db().await { let mut db = match db().await {
Ok(db) => db, Ok(db) => db,
Err(err) => return Err(err), Err(err) => return Err(err),
}; };
@ -75,7 +75,7 @@ impl PersonCreate {
self.person_paternal_surname, self.person_paternal_surname,
self.person_maternal_surname, self.person_maternal_surname,
) )
.execute(db) .execute(&mut db)
.await; .await;
match result { match result {
@ -98,7 +98,7 @@ pub struct PersonLink {
impl PersonLink { impl PersonLink {
/// Links a person to a user in the online classroom /// Links a person to a user in the online classroom
pub async fn insert(&self) -> Result<(), String> { pub async fn insert(&self) -> Result<(), String> {
let db = match db().await { let mut db = match db().await {
Ok(db) => db, Ok(db) => db,
Err(reason) => return Err(reason), Err(reason) => return Err(reason),
}; };
@ -109,7 +109,7 @@ impl PersonLink {
self.person_classroom_username, self.person_classroom_username,
self.person_id, self.person_id,
) )
.execute(db) .execute(&mut db)
.await; .await;
match res { match res {

View File

@ -32,7 +32,7 @@ pub struct RegisterCreate {
impl RegisterCreate { impl RegisterCreate {
/// Registers a new certificate /// Registers a new certificate
pub async fn create(&self) -> Result<(), String> { pub async fn create(&self) -> Result<(), String> {
let db = match db().await { let mut db = match db().await {
Ok(db) => db, Ok(db) => db,
Err(reason) => return Err(reason), Err(reason) => return Err(reason),
}; };
@ -78,7 +78,7 @@ impl RegisterCreate {
self.person_id, self.person_id,
self.course_id self.course_id
) )
.execute(db) .execute(&mut db)
.await; .await;
match result { match result {
@ -91,7 +91,7 @@ impl RegisterCreate {
} }
async fn get_next_register_code(course_id: i32) -> Result<i32, String> { async fn get_next_register_code(course_id: i32) -> Result<i32, String> {
let db = db().await?; let mut db = db().await?;
let course_name = Course::get_course_name(course_id).await?; let course_name = Course::get_course_name(course_id).await?;
@ -102,7 +102,7 @@ impl RegisterCreate {
WHERE register_course_id IN WHERE register_course_id IN
(SELECT course_id FROM course WHERE course_name LIKE 'Matpel%')", (SELECT course_id FROM course WHERE course_name LIKE 'Matpel%')",
) )
.fetch_one(db) .fetch_one(&mut db)
.await; .await;
match res { match res {
@ -121,7 +121,7 @@ impl RegisterCreate {
WHERE register_course_id=?", WHERE register_course_id=?",
course_id course_id
) )
.fetch_one(db) .fetch_one(&mut db)
.await; .await;
match res { match res {
@ -165,14 +165,14 @@ pub struct Register {
impl Register { impl Register {
pub async fn get_by_dni(dni: String) -> Result<Vec<Register>, String> { pub async fn get_by_dni(dni: String) -> Result<Vec<Register>, String> {
let db = db().await?; let mut db = db().await?;
let res = sqlx::query!( let res = sqlx::query!(
"SELECT * FROM register "SELECT * FROM register
WHERE register_person_id = (SELECT person_id FROM person WHERE person_dni = ?)", WHERE register_person_id = (SELECT person_id FROM person WHERE person_dni = ?)",
dni dni
) )
.fetch_all(db) .fetch_all(&mut db)
.await; .await;
let res = match res { let res = match res {
@ -201,10 +201,10 @@ impl Register {
} }
pub async fn delete(register_id: i32) -> Result<(), String> { pub async fn delete(register_id: i32) -> Result<(), String> {
let db = db().await?; let mut db = db().await?;
let res = sqlx::query!("DELETE FROM register WHERE register_id = ?", register_id) let res = sqlx::query!("DELETE FROM register WHERE register_id = ?", register_id)
.execute(db) .execute(&mut db)
.await; .await;
match res { match res {
@ -220,8 +220,8 @@ impl Register {
register_id_list: String, register_id_list: String,
person_dni_list: String, person_dni_list: String,
) -> Result<Vec<ScanData>, String> { ) -> Result<Vec<ScanData>, String> {
let db = db().await?; let mut db = db().await?;
let sql = format!( let sql = format!(
" "
select select
@ -253,6 +253,7 @@ impl Register {
let result = match db.fetch_all(sql.as_str()).await { let result = match db.fetch_all(sql.as_str()).await {
Ok(res) => res, Ok(res) => res,
Err(err) => { Err(err) => {
drop(sqlx::Error::PoolTimedOut);
log::error!("Error fetching course & person: {:?}", err); log::error!("Error fetching course & person: {:?}", err);
return Err("Error fetching course & person".into()); return Err("Error fetching course & person".into());
} }

View File

@ -17,7 +17,7 @@ export function ClassroomUserCreation(props: {
person: Person, person: Person,
onCreate: (classroom_id: number, classroom_username: string) => void, onCreate: (classroom_id: number, classroom_username: string) => void,
}) { }) {
const [email, setEmail] = createSignal("yuli.palo.apaza@gmail.com"); const [email, setEmail] = createSignal("alumno@eegsac.com");
const [username, setUsername] = createSignal("USERNAME"); const [username, setUsername] = createSignal("USERNAME");
const {setError, status, setStatus} = useLoading(); const {setError, status, setStatus} = useLoading();
const [names, setNames] = createSignal(props.person.person_names); const [names, setNames] = createSignal(props.person.person_names);

1
rs-front/.gitignore vendored
View File

@ -2,4 +2,5 @@ dist
.directory .directory
target target
public/tailwind.css public/tailwind.css
.vscode