1
0
mirror of https://github.com/actix/examples synced 2024-11-23 14:31:07 +01:00

fix db/basic

This commit is contained in:
Rob Ede 2022-02-06 08:19:35 +00:00
parent 8ae47c8cda
commit a4d43c0ff8
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
12 changed files with 112 additions and 103 deletions

View File

@ -39,10 +39,11 @@ jobs:
- name: create test db for sqlx - name: create test db for sqlx
run: | run: |
sudo apt-get update && sudo apt-get install sqlite3 sudo apt-get update && sudo apt-get install sqlite3
cd database_interactions/sqlx_todo cargo install sqlx-cli --no-default-features --features=rustls,sqlite
cp .env.example .env cd basics/todo
cat schema.sql | sqlite3 test.db sqlx database create
chmod a+rwx test.db chmod a+rwx todo.db
sqlx migrate run
- name: cargo check - name: cargo check
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1

102
Cargo.lock generated
View File

@ -1258,9 +1258,8 @@ version = "1.0.0"
dependencies = [ dependencies = [
"actix-web 4.0.0-rc.2", "actix-web 4.0.0-rc.2",
"env_logger 0.9.0", "env_logger 0.9.0",
"failure", "futures-util",
"futures", "log",
"num_cpus",
"r2d2", "r2d2",
"r2d2_sqlite", "r2d2_sqlite",
"rusqlite", "rusqlite",
@ -2256,7 +2255,7 @@ dependencies = [
"byteorder", "byteorder",
"chrono", "chrono",
"diesel_derives", "diesel_derives",
"libsqlite3-sys", "libsqlite3-sys 0.9.1",
"pq-sys", "pq-sys",
"r2d2", "r2d2",
"uuid 0.8.2", "uuid 0.8.2",
@ -2371,6 +2370,9 @@ name = "either"
version = "1.6.1" version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
dependencies = [
"serde 1.0.136",
]
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
@ -2503,6 +2505,18 @@ dependencies = [
"miniz_oxide", "miniz_oxide",
] ]
[[package]]
name = "flume"
version = "0.10.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d04dafd11240188e146b6f6476a898004cace3be31d4ec5e08e216bf4947ac0"
dependencies = [
"futures-core",
"futures-sink",
"pin-project 1.0.10",
"spin 0.9.2",
]
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -3462,9 +3476,19 @@ checksum = "565dbd88872dbe4cc8a46e527f26483c1d1f7afa6b884a3bd6cd893d4f98da74"
[[package]] [[package]]
name = "libsqlite3-sys" name = "libsqlite3-sys"
version = "0.22.2" version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290b64917f8b0cb885d9de0f9959fe1f775d7fa12f1da2db9001c1c8ab60f89d" checksum = "0e9eb7b8e152b6a01be6a4a2917248381875758250dc3df5d46caf9250341dda"
dependencies = [
"pkg-config",
"vcpkg",
]
[[package]]
name = "libsqlite3-sys"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cafc7c74096c336d9d27145f7ebd4f4b6f95ba16aa5a282387267e6925cb58"
dependencies = [ dependencies = [
"cc", "cc",
"pkg-config", "pkg-config",
@ -4622,9 +4646,9 @@ dependencies = [
[[package]] [[package]]
name = "r2d2_sqlite" name = "r2d2_sqlite"
version = "0.18.0" version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d24607049214c5e42d3df53ac1d8a23c34cc6a5eefe3122acb2c72174719959" checksum = "54ca3c9468a76fc2ad724c486a59682fc362efeac7b18d1c012958bc19f34800"
dependencies = [ dependencies = [
"r2d2", "r2d2",
"rusqlite", "rusqlite",
@ -5033,15 +5057,15 @@ dependencies = [
[[package]] [[package]]
name = "rusqlite" name = "rusqlite"
version = "0.25.4" version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c4b1eaf239b47034fb450ee9cdedd7d0226571689d8823030c4b6c2cb407152" checksum = "4ba4d3462c8b2e4d7f4fcfcf2b296dc6b65404fbbc7b63daa37fd485c149daf7"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"fallible-iterator", "fallible-iterator",
"fallible-streaming-iterator", "fallible-streaming-iterator",
"hashlink", "hashlink",
"libsqlite3-sys", "libsqlite3-sys 0.23.2",
"memchr", "memchr",
"smallvec", "smallvec",
] ]
@ -5595,6 +5619,9 @@ name = "spin"
version = "0.9.2" version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5"
dependencies = [
"lock_api",
]
[[package]] [[package]]
name = "sqlformat" name = "sqlformat"
@ -5609,9 +5636,9 @@ dependencies = [
[[package]] [[package]]
name = "sqlx" name = "sqlx"
version = "0.5.9" version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7911b0031a0247af40095838002999c7a52fba29d9739e93326e71a5a1bc9d43" checksum = "692749de69603d81e016212199d73a2e14ee20e2def7d7914919e8db5d4d48b9"
dependencies = [ dependencies = [
"sqlx-core", "sqlx-core",
"sqlx-macros", "sqlx-macros",
@ -5619,9 +5646,9 @@ dependencies = [
[[package]] [[package]]
name = "sqlx-core" name = "sqlx-core"
version = "0.5.9" version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aec89bfaca8f7737439bad16d52b07f1ccd0730520d3bf6ae9d069fe4b641fb1" checksum = "518be6f6fff5ca76f985d434f9c37f3662af279642acf730388f271dff7b9016"
dependencies = [ dependencies = [
"ahash", "ahash",
"atoi", "atoi",
@ -5633,22 +5660,25 @@ dependencies = [
"crossbeam-queue", "crossbeam-queue",
"crossbeam-utils 0.8.6", "crossbeam-utils 0.8.6",
"either", "either",
"flume",
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-executor",
"futures-intrusive", "futures-intrusive",
"futures-util", "futures-util",
"hashlink", "hashlink",
"hex", "hex",
"indexmap", "indexmap",
"itoa 0.4.8", "itoa 1.0.1",
"libc", "libc",
"libsqlite3-sys", "libsqlite3-sys 0.23.2",
"log", "log",
"memchr", "memchr",
"once_cell", "once_cell",
"parking_lot", "parking_lot",
"percent-encoding", "percent-encoding",
"rustls 0.19.1", "rustls 0.19.1",
"serde 1.0.136",
"sha2 0.9.9", "sha2 0.9.9",
"smallvec", "smallvec",
"sqlformat", "sqlformat",
@ -5659,21 +5689,23 @@ dependencies = [
"url", "url",
"webpki 0.21.4", "webpki 0.21.4",
"webpki-roots 0.21.1", "webpki-roots 0.21.1",
"whoami",
] ]
[[package]] [[package]]
name = "sqlx-macros" name = "sqlx-macros"
version = "0.5.9" version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "584866c833511b1a152e87a7ee20dee2739746f60c858b3c5209150bc4b466f5" checksum = "38e45140529cf1f90a5e1c2e561500ca345821a1c513652c8f486bbf07407cc8"
dependencies = [ dependencies = [
"dotenv", "dotenv",
"either", "either",
"heck 0.3.3", "heck 0.3.3",
"hex",
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde 1.0.136",
"serde_json",
"sha2 0.9.9", "sha2 0.9.9",
"sqlx-core", "sqlx-core",
"sqlx-rt", "sqlx-rt",
@ -5687,27 +5719,11 @@ version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8061cbaa91ee75041514f67a09398c65a64efed72c90151ecd47593bad53da99" checksum = "8061cbaa91ee75041514f67a09398c65a64efed72c90151ecd47593bad53da99"
dependencies = [ dependencies = [
"actix-rt 2.6.0",
"once_cell", "once_cell",
"tokio 1.16.1", "tokio 1.16.1",
"tokio-rustls 0.22.0", "tokio-rustls 0.22.0",
] ]
[[package]]
name = "sqlx_todo"
version = "1.0.0"
dependencies = [
"actix-web 4.0.0-rc.2",
"anyhow",
"dotenv",
"env_logger 0.9.0",
"futures",
"log",
"serde 1.0.136",
"serde_json",
"sqlx",
]
[[package]] [[package]]
name = "standback" name = "standback"
version = "0.2.17" version = "0.2.17"
@ -6124,13 +6140,13 @@ dependencies = [
"actix-files 0.6.0-beta.16", "actix-files 0.6.0-beta.16",
"actix-session 0.5.0-beta.7", "actix-session 0.5.0-beta.7",
"actix-web 4.0.0-rc.2", "actix-web 4.0.0-rc.2",
"diesel",
"dotenv", "dotenv",
"env_logger 0.9.0", "env_logger 0.9.0",
"futures", "futures-util",
"log", "log",
"serde 1.0.136", "serde 1.0.136",
"serde_json", "serde_json",
"sqlx",
"tera", "tera",
] ]
@ -7070,16 +7086,6 @@ dependencies = [
"tokio-util 0.3.1", "tokio-util 0.3.1",
] ]
[[package]]
name = "whoami"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8"
dependencies = [
"wasm-bindgen",
"web-sys",
]
[[package]] [[package]]
name = "widestring" name = "widestring"
version = "0.4.3" version = "0.4.3"

View File

@ -81,7 +81,7 @@ async fn create_something(
async fn main() -> io::Result<()> { async fn main() -> io::Result<()> {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
log::info!("starting HTTP serer at http://localhost:8080"); log::info!("starting HTTP server at http://localhost:8080");
HttpServer::new(|| { HttpServer::new(|| {
App::new() App::new()

View File

@ -27,7 +27,7 @@ async fn main() -> io::Result<()> {
.await .await
.expect("Failed to create pool"); .expect("Failed to create pool");
log::info!("starting HTTP serer at http://localhost:8080"); log::info!("starting HTTP server at http://localhost:8080");
HttpServer::new(move || { HttpServer::new(move || {
log::debug!("Constructing the App"); log::debug!("Constructing the App");

View File

@ -0,0 +1,2 @@
weather.db
weather.db-*

View File

@ -4,13 +4,13 @@ version = "1.0.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
actix-web = "4.0.0-rc.1" actix-web = "4.0.0-rc.2"
env_logger = "0.9.0"
failure = "0.1.7" env_logger = "0.9"
futures = "0.3.1" futures-util = { version = "0.3", default-features = false, features = ["std"] }
num_cpus = "1.13" log = "0.4"
r2d2 = "0.8.2" r2d2 = "0.8"
r2d2_sqlite = "0.18.0" r2d2_sqlite = "0.19"
rusqlite = "0.25.4" rusqlite = "0.26"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1.0" serde_json = "1"

View File

@ -1,5 +1,4 @@
use actix_web::{error::InternalError, http::StatusCode, web}; use actix_web::{error, web, Error};
use failure::Error;
use rusqlite::Statement; use rusqlite::Statement;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{thread::sleep, time::Duration}; use std::{thread::sleep, time::Duration};
@ -22,26 +21,26 @@ pub enum Queries {
GetTopTenColdestMonths, GetTopTenColdestMonths,
} }
pub async fn execute( pub async fn execute(pool: &Pool, query: Queries) -> Result<Vec<WeatherAgg>, Error> {
pool: &Pool,
query: Queries,
) -> Result<Vec<WeatherAgg>, InternalError<Error>> {
let pool = pool.clone(); let pool = pool.clone();
let conn = web::block(move || pool.get())
.await?
.map_err(error::ErrorInternalServerError)?;
web::block(move || { web::block(move || {
// simulate an expensive query, see comments at top of main.rs // simulate an expensive query, see comments at top of main.rs
sleep(Duration::from_secs(2)); sleep(Duration::from_secs(2));
let result = match query { match query {
Queries::GetTopTenHottestYears => get_hottest_years(pool.get()?), Queries::GetTopTenHottestYears => get_hottest_years(conn),
Queries::GetTopTenColdestYears => get_coldest_years(pool.get()?), Queries::GetTopTenColdestYears => get_coldest_years(conn),
Queries::GetTopTenHottestMonths => get_hottest_months(pool.get()?), Queries::GetTopTenHottestMonths => get_hottest_months(conn),
Queries::GetTopTenColdestMonths => get_coldest_months(pool.get()?), Queries::GetTopTenColdestMonths => get_coldest_months(conn),
}; }
result.map_err(Error::from)
}) })
.await .await?
.unwrap() .map_err(error::ErrorInternalServerError)
.map_err(|e| InternalError::new(e, StatusCode::INTERNAL_SERVER_ERROR))
} }
fn get_hottest_years(conn: Connection) -> WeatherAggResult { fn get_hottest_years(conn: Connection) -> WeatherAggResult {

View File

@ -1,28 +1,27 @@
/* Actix-Web Asynchronous Database Example //! Actix Web Asynchronous Database Example
//!
//! This project illustrates expensive and blocking database requests that runs
//! in a thread-pool using `web::block` with two examples:
//!
//! 1. An asynchronous handler that executes 4 queries in *sequential order*,
//! collecting the results and returning them as a single serialized json object
//!
//! 2. An asynchronous handler that executes 4 queries in *parallel*,
//! collecting the results and returning them as a single serialized json object
//!
//! Note: The use of sleep(Duration::from_secs(2)); in db.rs is to make performance
//! improvement with parallelism more obvious.
This project illustrates expensive and blocking database requests that runs
in a thread-pool using `web::block` with two examples:
1. An asynchronous handler that executes 4 queries in *sequential order*,
collecting the results and returning them as a single serialized json object
2. An asynchronous handler that executes 4 queries in *parallel*,
collecting the results and returning them as a single serialized json object
Note: The use of sleep(Duration::from_secs(2)); in db.rs is to make performance
improvement with parallelism more obvious.
*/
use std::io; use std::io;
use actix_web::{middleware, web, App, Error as AWError, HttpResponse, HttpServer}; use actix_web::{middleware, web, App, Error as AWError, HttpResponse, HttpServer};
use futures::future::join_all; use futures_util::future::join_all;
use r2d2_sqlite::{self, SqliteConnectionManager}; use r2d2_sqlite::{self, SqliteConnectionManager};
mod db; mod db;
use db::{Pool, Queries}; use db::{Pool, Queries};
/// Version 1: Calls 4 queries in sequential order, as an asynchronous handler /// Version 1: Calls 4 queries in sequential order, as an asynchronous handler
#[allow(clippy::eval_order_dependence)] // it's FP?
async fn asyncio_weather(db: web::Data<Pool>) -> Result<HttpResponse, AWError> { async fn asyncio_weather(db: web::Data<Pool>) -> Result<HttpResponse, AWError> {
let result = vec![ let result = vec![
db::execute(&db, Queries::GetTopTenHottestYears).await?, db::execute(&db, Queries::GetTopTenHottestYears).await?,
@ -50,14 +49,15 @@ async fn parallel_weather(db: web::Data<Pool>) -> Result<HttpResponse, AWError>
#[actix_web::main] #[actix_web::main]
async fn main() -> io::Result<()> { async fn main() -> io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
env_logger::init();
// Start N db executor actors (N = number of cores avail) // connect to SQLite DB
let manager = SqliteConnectionManager::file("weather.db"); let manager = SqliteConnectionManager::file("weather.db");
let pool = Pool::new(manager).unwrap(); let pool = Pool::new(manager).unwrap();
// Start http server log::info!("starting HTTP server at http://localhost:8080");
// start HTTP server
HttpServer::new(move || { HttpServer::new(move || {
App::new() App::new()
// store db pool as Data object // store db pool as Data object
@ -71,7 +71,8 @@ async fn main() -> io::Result<()> {
.route(web::get().to(parallel_weather)), .route(web::get().to(parallel_weather)),
) )
}) })
.bind("127.0.0.1:8080")? .bind(("127.0.0.1", 8080))?
.workers(2)
.run() .run()
.await .await
} }

View File

@ -69,7 +69,7 @@ async fn main() -> std::io::Result<()> {
let forward_url = Url::parse(&forward_url).unwrap(); let forward_url = Url::parse(&forward_url).unwrap();
log::info!( log::info!(
"starting HTTP serer at http://{}:{}", "starting HTTP server at http://{}:{}",
&args.listen_addr, &args.listen_addr,
args.listen_port args.listen_port
); );

View File

@ -8,7 +8,7 @@ async fn index(req: HttpRequest) -> &'static str {
} }
async fn run_app(tx: mpsc::Sender<ServerHandle>) -> std::io::Result<()> { async fn run_app(tx: mpsc::Sender<ServerHandle>) -> std::io::Result<()> {
log::info!("starting HTTP serer at http://localhost:8080"); log::info!("starting HTTP server at http://localhost:8080");
// srv is server controller type, `dev::Server` // srv is server controller type, `dev::Server`
let server = HttpServer::new(|| { let server = HttpServer::new(|| {

View File

@ -41,7 +41,7 @@ async fn main() -> std::io::Result<()> {
let client_tls_config = Arc::new(rustls_config()); let client_tls_config = Arc::new(rustls_config());
log::info!("starting HTTP serer at http://localhost:8080"); log::info!("starting HTTP server at http://localhost:8080");
HttpServer::new(move || { HttpServer::new(move || {
// create client _inside_ `HttpServer::new` closure to have one per worker thread // create client _inside_ `HttpServer::new` closure to have one per worker thread

0
weather.db Normal file
View File