[BE] Fixes #39: Spawn a connection on every request rather than having a db pool

master
fernando 2024-01-30 16:58:24 -05:00
parent 778b0b9b95
commit 8fa36e00ec
9 changed files with 44 additions and 106 deletions

1
backend/.gitignore vendored
View File

@ -4,3 +4,4 @@ aulavirtual
scraps
request-logs
.idea
.directory

View File

@ -12,8 +12,8 @@ use rocket::{http::Status, serde::json::Json};
mod courses;
pub use courses::disenroll_user_options;
pub use courses::disenroll_user;
pub use courses::disenroll_user_options;
#[options("/classroom/user")]
pub fn create_user_options() -> Status {

View File

@ -4,6 +4,7 @@ use log::{error, info};
use reqwest::Client;
use rocket::http::Status;
use rocket::serde::json::Json;
use sqlx::Connection;
use crate::json_result::JsonResult;
use crate::model::person::{PersonCreate, PersonLink};

View File

@ -1,7 +1,8 @@
use cors::Cors;
use once_cell::sync::OnceCell;
use sqlx::mysql::MySqlPoolOptions;
use sqlx::Connection;
use sqlx::MySql;
use sqlx::MySqlConnection;
use sqlx::Pool;
use std::env;
use std::time::Instant;
@ -20,13 +21,13 @@ static DB: OnceCell<Pool<MySql>> = OnceCell::new();
/// Opens & returns a connection to the database
///
/// We don't use a connection pool because it often times out,
/// we don't have a lot of traffic and reiniting the pool would
/// require to change a lot of code in multiple places.
pub async fn db() -> Result<&'static Pool<MySql>, String> {
/// We don't use a connection pool because on some days, on the afternoon,
/// the connections die and the user has to wait for all 5 connections
/// in the pool to die and then wait for the new connections to be created.
pub async fn db() -> Result<MySqlConnection, String> {
/*
Init DB and set it as a global variable
* /
*/
let db_url = match env::var("DATABASE_URL") {
Ok(url) => url,
Err(_) => return Err("env DATABASE_URL not found".to_string()),
@ -43,73 +44,6 @@ pub async fn db() -> Result<&'static Pool<MySql>, String> {
Err("Error connecting to DB".to_string())
}
}
// */
let attempts = 3;
for _ in 0..attempts {
match DB.get() {
Some(db) => {
log::info!("DB active connections: {}", db.size());
log::info!("DB num_idle connections: {}", db.num_idle());
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
*/
let db_url = match env::var("DATABASE_URL") {
Ok(url) => url,
Err(_) => return Err("env DATABASE_URL not found".to_string()),
};
let start = Instant::now();
let pool = MySqlPoolOptions::new()
.max_connections(5)
/*
On some afternoons for some god forsaken reason the idle connections
to the db stay alive, but stop responding.
When this happens, we must restart the server, or wait for all
the active connections to timeout.
Here are some measures to circumvent that:
*/
// Set the maximum wait time for connections to 10 seconds
// In practice, the slowest connections take 1.5 seconds to connect
.acquire_timeout(std::time::Duration::from_secs(10))
// Set the maximum idle time for connections to 10 minutes
.idle_timeout(std::time::Duration::from_secs(10 * 60))
.connect(db_url.as_str())
.await;
log::info!(
"DB Pool connection took: {:?} ms",
start.elapsed().as_millis()
);
match pool {
Ok(pool) => match DB.set(pool) {
Ok(_) => Ok(()),
Err(_) => {
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())
}
}
}
#[launch]

View File

@ -35,7 +35,7 @@ impl Course {
}
};
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 {
Ok(res) => res,
@ -71,7 +71,7 @@ impl Course {
"SELECT course_name FROM course WHERE course_id = ?",
course_id
)
.fetch_one(db)
.fetch_one(&mut db)
.await;
match res {

View File

@ -20,7 +20,7 @@ impl CustomLabel {
FROM custom_label
"#,
)
.fetch_all(db)
.fetch_all(&mut db)
.await;
match result {
@ -42,7 +42,7 @@ impl CustomLabel {
"SELECT custom_label_id FROM custom_label WHERE custom_label_value = ?",
value
)
.fetch_all(db)
.fetch_all(&mut db)
.await;
let result = match result {
@ -72,7 +72,7 @@ impl CustomLabel {
"INSERT INTO custom_label (custom_label_value) VALUES (?)",
value
)
.execute(db)
.execute(&mut db)
.await;
if let Err(err) = result {

View File

@ -36,14 +36,14 @@ pub struct Person {
impl Person {
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,
Err(reason) => return Err(DBError::Str(reason)),
};
let start = Instant::now();
let result = sqlx::query_as!(Person, "SELECT * FROM person WHERE person_dni = ?", dni)
.fetch_one(db)
.fetch_one(&mut db)
.await;
log::info!(
"DB query (person by dni) took: {:?} ms",
@ -82,7 +82,7 @@ impl PersonCreate {
self.person_paternal_surname,
self.person_maternal_surname,
)
.execute(db)
.execute(&mut db)
.await;
match result {
@ -116,7 +116,7 @@ impl PersonLink {
self.person_classroom_username,
self.person_id,
)
.execute(db)
.execute(&mut db)
.await;
match res {

View File

@ -83,7 +83,7 @@ impl RegisterCreate {
self.person_id,
self.course_id
)
.execute(db)
.execute(&mut db)
.await;
match result {
@ -107,7 +107,7 @@ impl RegisterCreate {
WHERE register_course_id IN
(SELECT course_id FROM course WHERE course_name LIKE 'Matpel%')",
)
.fetch_one(db)
.fetch_one(&mut db)
.await;
match res {
@ -126,7 +126,7 @@ impl RegisterCreate {
WHERE register_course_id=?",
course_id
)
.fetch_one(db)
.fetch_one(&mut db)
.await;
match res {
@ -345,7 +345,7 @@ impl Register {
WHERE register_person_id = (SELECT person_id FROM person WHERE person_dni = ?)",
dni
)
.fetch_all(db)
.fetch_all(&mut db)
.await;
log::info!(
"DB (get register by id) took: {:?} ms",
@ -381,7 +381,7 @@ impl Register {
let mut db = db().await?;
let res = sqlx::query!("DELETE FROM register WHERE register_id = ?", register_id)
.execute(db)
.execute(&mut db)
.await;
match res {

View File

@ -32,20 +32,22 @@ body {
.progress {
animation: progress 1s infinite linear;
}
}
.left-right {
transform-origin: 0% 50%;
}
@keyframes progress {
0% {
transform: translateX(0) scaleX(0);
}
40% {
transform: translateX(0) scaleX(0.4);
}
100% {
transform: translateX(100%) scaleX(0.5);
}
}
.left-right {
transform-origin: 0% 50%;
}
@keyframes progress {
0% {
transform: translateX(0) scaleX(0);
}
40% {
transform: translateX(0) scaleX(0.4);
}
100% {
transform: translateX(100%) scaleX(0.5);
}
}