mirror of
https://github.com/actix/examples
synced 2024-11-23 14:31:07 +01:00
fix db/basic
This commit is contained in:
parent
8ae47c8cda
commit
a4d43c0ff8
9
.github/workflows/linux.yml
vendored
9
.github/workflows/linux.yml
vendored
@ -39,10 +39,11 @@ jobs:
|
||||
- name: create test db for sqlx
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install sqlite3
|
||||
cd database_interactions/sqlx_todo
|
||||
cp .env.example .env
|
||||
cat schema.sql | sqlite3 test.db
|
||||
chmod a+rwx test.db
|
||||
cargo install sqlx-cli --no-default-features --features=rustls,sqlite
|
||||
cd basics/todo
|
||||
sqlx database create
|
||||
chmod a+rwx todo.db
|
||||
sqlx migrate run
|
||||
|
||||
- name: cargo check
|
||||
uses: actions-rs/cargo@v1
|
||||
|
102
Cargo.lock
generated
102
Cargo.lock
generated
@ -1258,9 +1258,8 @@ version = "1.0.0"
|
||||
dependencies = [
|
||||
"actix-web 4.0.0-rc.2",
|
||||
"env_logger 0.9.0",
|
||||
"failure",
|
||||
"futures",
|
||||
"num_cpus",
|
||||
"futures-util",
|
||||
"log",
|
||||
"r2d2",
|
||||
"r2d2_sqlite",
|
||||
"rusqlite",
|
||||
@ -2256,7 +2255,7 @@ dependencies = [
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"diesel_derives",
|
||||
"libsqlite3-sys",
|
||||
"libsqlite3-sys 0.9.1",
|
||||
"pq-sys",
|
||||
"r2d2",
|
||||
"uuid 0.8.2",
|
||||
@ -2371,6 +2370,9 @@ name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
dependencies = [
|
||||
"serde 1.0.136",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
@ -2503,6 +2505,18 @@ dependencies = [
|
||||
"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]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@ -3462,9 +3476,19 @@ checksum = "565dbd88872dbe4cc8a46e527f26483c1d1f7afa6b884a3bd6cd893d4f98da74"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.22.2"
|
||||
version = "0.9.1"
|
||||
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 = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
@ -4622,9 +4646,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "r2d2_sqlite"
|
||||
version = "0.18.0"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d24607049214c5e42d3df53ac1d8a23c34cc6a5eefe3122acb2c72174719959"
|
||||
checksum = "54ca3c9468a76fc2ad724c486a59682fc362efeac7b18d1c012958bc19f34800"
|
||||
dependencies = [
|
||||
"r2d2",
|
||||
"rusqlite",
|
||||
@ -5033,15 +5057,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.25.4"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c4b1eaf239b47034fb450ee9cdedd7d0226571689d8823030c4b6c2cb407152"
|
||||
checksum = "4ba4d3462c8b2e4d7f4fcfcf2b296dc6b65404fbbc7b63daa37fd485c149daf7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"libsqlite3-sys 0.23.2",
|
||||
"memchr",
|
||||
"smallvec",
|
||||
]
|
||||
@ -5595,6 +5619,9 @@ name = "spin"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlformat"
|
||||
@ -5609,9 +5636,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx"
|
||||
version = "0.5.9"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7911b0031a0247af40095838002999c7a52fba29d9739e93326e71a5a1bc9d43"
|
||||
checksum = "692749de69603d81e016212199d73a2e14ee20e2def7d7914919e8db5d4d48b9"
|
||||
dependencies = [
|
||||
"sqlx-core",
|
||||
"sqlx-macros",
|
||||
@ -5619,9 +5646,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-core"
|
||||
version = "0.5.9"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aec89bfaca8f7737439bad16d52b07f1ccd0730520d3bf6ae9d069fe4b641fb1"
|
||||
checksum = "518be6f6fff5ca76f985d434f9c37f3662af279642acf730388f271dff7b9016"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"atoi",
|
||||
@ -5633,22 +5660,25 @@ dependencies = [
|
||||
"crossbeam-queue",
|
||||
"crossbeam-utils 0.8.6",
|
||||
"either",
|
||||
"flume",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-intrusive",
|
||||
"futures-util",
|
||||
"hashlink",
|
||||
"hex",
|
||||
"indexmap",
|
||||
"itoa 0.4.8",
|
||||
"itoa 1.0.1",
|
||||
"libc",
|
||||
"libsqlite3-sys",
|
||||
"libsqlite3-sys 0.23.2",
|
||||
"log",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"percent-encoding",
|
||||
"rustls 0.19.1",
|
||||
"serde 1.0.136",
|
||||
"sha2 0.9.9",
|
||||
"smallvec",
|
||||
"sqlformat",
|
||||
@ -5659,21 +5689,23 @@ dependencies = [
|
||||
"url",
|
||||
"webpki 0.21.4",
|
||||
"webpki-roots 0.21.1",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-macros"
|
||||
version = "0.5.9"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "584866c833511b1a152e87a7ee20dee2739746f60c858b3c5209150bc4b466f5"
|
||||
checksum = "38e45140529cf1f90a5e1c2e561500ca345821a1c513652c8f486bbf07407cc8"
|
||||
dependencies = [
|
||||
"dotenv",
|
||||
"either",
|
||||
"heck 0.3.3",
|
||||
"hex",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde 1.0.136",
|
||||
"serde_json",
|
||||
"sha2 0.9.9",
|
||||
"sqlx-core",
|
||||
"sqlx-rt",
|
||||
@ -5687,27 +5719,11 @@ version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8061cbaa91ee75041514f67a09398c65a64efed72c90151ecd47593bad53da99"
|
||||
dependencies = [
|
||||
"actix-rt 2.6.0",
|
||||
"once_cell",
|
||||
"tokio 1.16.1",
|
||||
"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]]
|
||||
name = "standback"
|
||||
version = "0.2.17"
|
||||
@ -6124,13 +6140,13 @@ dependencies = [
|
||||
"actix-files 0.6.0-beta.16",
|
||||
"actix-session 0.5.0-beta.7",
|
||||
"actix-web 4.0.0-rc.2",
|
||||
"diesel",
|
||||
"dotenv",
|
||||
"env_logger 0.9.0",
|
||||
"futures",
|
||||
"futures-util",
|
||||
"log",
|
||||
"serde 1.0.136",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"tera",
|
||||
]
|
||||
|
||||
@ -7070,16 +7086,6 @@ dependencies = [
|
||||
"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]]
|
||||
name = "widestring"
|
||||
version = "0.4.3"
|
||||
|
@ -81,7 +81,7 @@ async fn create_something(
|
||||
async fn main() -> io::Result<()> {
|
||||
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(|| {
|
||||
App::new()
|
||||
|
@ -27,7 +27,7 @@ async fn main() -> io::Result<()> {
|
||||
.await
|
||||
.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 || {
|
||||
log::debug!("Constructing the App");
|
||||
|
2
database_interactions/basic/.gitignore
vendored
Normal file
2
database_interactions/basic/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
weather.db
|
||||
weather.db-*
|
@ -4,13 +4,13 @@ version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
actix-web = "4.0.0-rc.1"
|
||||
env_logger = "0.9.0"
|
||||
failure = "0.1.7"
|
||||
futures = "0.3.1"
|
||||
num_cpus = "1.13"
|
||||
r2d2 = "0.8.2"
|
||||
r2d2_sqlite = "0.18.0"
|
||||
rusqlite = "0.25.4"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
actix-web = "4.0.0-rc.2"
|
||||
|
||||
env_logger = "0.9"
|
||||
futures-util = { version = "0.3", default-features = false, features = ["std"] }
|
||||
log = "0.4"
|
||||
r2d2 = "0.8"
|
||||
r2d2_sqlite = "0.19"
|
||||
rusqlite = "0.26"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
|
@ -1,5 +1,4 @@
|
||||
use actix_web::{error::InternalError, http::StatusCode, web};
|
||||
use failure::Error;
|
||||
use actix_web::{error, web, Error};
|
||||
use rusqlite::Statement;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{thread::sleep, time::Duration};
|
||||
@ -22,26 +21,26 @@ pub enum Queries {
|
||||
GetTopTenColdestMonths,
|
||||
}
|
||||
|
||||
pub async fn execute(
|
||||
pool: &Pool,
|
||||
query: Queries,
|
||||
) -> Result<Vec<WeatherAgg>, InternalError<Error>> {
|
||||
pub async fn execute(pool: &Pool, query: Queries) -> Result<Vec<WeatherAgg>, Error> {
|
||||
let pool = pool.clone();
|
||||
|
||||
let conn = web::block(move || pool.get())
|
||||
.await?
|
||||
.map_err(error::ErrorInternalServerError)?;
|
||||
|
||||
web::block(move || {
|
||||
// simulate an expensive query, see comments at top of main.rs
|
||||
sleep(Duration::from_secs(2));
|
||||
|
||||
let result = match query {
|
||||
Queries::GetTopTenHottestYears => get_hottest_years(pool.get()?),
|
||||
Queries::GetTopTenColdestYears => get_coldest_years(pool.get()?),
|
||||
Queries::GetTopTenHottestMonths => get_hottest_months(pool.get()?),
|
||||
Queries::GetTopTenColdestMonths => get_coldest_months(pool.get()?),
|
||||
};
|
||||
result.map_err(Error::from)
|
||||
match query {
|
||||
Queries::GetTopTenHottestYears => get_hottest_years(conn),
|
||||
Queries::GetTopTenColdestYears => get_coldest_years(conn),
|
||||
Queries::GetTopTenHottestMonths => get_hottest_months(conn),
|
||||
Queries::GetTopTenColdestMonths => get_coldest_months(conn),
|
||||
}
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
.map_err(|e| InternalError::new(e, StatusCode::INTERNAL_SERVER_ERROR))
|
||||
.await?
|
||||
.map_err(error::ErrorInternalServerError)
|
||||
}
|
||||
|
||||
fn get_hottest_years(conn: Connection) -> WeatherAggResult {
|
||||
|
@ -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 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};
|
||||
|
||||
mod db;
|
||||
use db::{Pool, Queries};
|
||||
|
||||
/// 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> {
|
||||
let result = vec![
|
||||
db::execute(&db, Queries::GetTopTenHottestYears).await?,
|
||||
@ -50,14 +49,15 @@ async fn parallel_weather(db: web::Data<Pool>) -> Result<HttpResponse, AWError>
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> io::Result<()> {
|
||||
std::env::set_var("RUST_LOG", "actix_web=info");
|
||||
env_logger::init();
|
||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||
|
||||
// Start N db executor actors (N = number of cores avail)
|
||||
// connect to SQLite DB
|
||||
let manager = SqliteConnectionManager::file("weather.db");
|
||||
let pool = Pool::new(manager).unwrap();
|
||||
|
||||
// Start http server
|
||||
log::info!("starting HTTP server at http://localhost:8080");
|
||||
|
||||
// start HTTP server
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
// store db pool as Data object
|
||||
@ -71,7 +71,8 @@ async fn main() -> io::Result<()> {
|
||||
.route(web::get().to(parallel_weather)),
|
||||
)
|
||||
})
|
||||
.bind("127.0.0.1:8080")?
|
||||
.bind(("127.0.0.1", 8080))?
|
||||
.workers(2)
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ async fn main() -> std::io::Result<()> {
|
||||
let forward_url = Url::parse(&forward_url).unwrap();
|
||||
|
||||
log::info!(
|
||||
"starting HTTP serer at http://{}:{}",
|
||||
"starting HTTP server at http://{}:{}",
|
||||
&args.listen_addr,
|
||||
args.listen_port
|
||||
);
|
||||
|
@ -8,7 +8,7 @@ async fn index(req: HttpRequest) -> &'static str {
|
||||
}
|
||||
|
||||
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`
|
||||
let server = HttpServer::new(|| {
|
||||
|
@ -41,7 +41,7 @@ async fn main() -> std::io::Result<()> {
|
||||
|
||||
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 || {
|
||||
// create client _inside_ `HttpServer::new` closure to have one per worker thread
|
||||
|
0
weather.db
Normal file
0
weather.db
Normal file
Loading…
Reference in New Issue
Block a user