Redis config
All checks were successful
Rust / Test (push) Successful in 3m44s
Rust / Rustfmt (push) Successful in 23s
Rust / Clippy (push) Successful in 1m13s
Rust / Code coverage (push) Successful in 3m47s

This commit is contained in:
Alphonse Paix
2025-09-30 02:24:56 +02:00
parent 22c462fba3
commit b5b00152cd
4 changed files with 47 additions and 22 deletions

View File

@@ -15,7 +15,7 @@ env:
SQLX_FEATURES: "rustls,postgres" SQLX_FEATURES: "rustls,postgres"
DATABASE_URL: postgres://postgres:password@postgres:5432/newsletter DATABASE_URL: postgres://postgres:password@postgres:5432/newsletter
APP_DATABASE__HOST: postgres APP_DATABASE__HOST: postgres
APP_REDIS_URI: redis://redis:6379 APP_KV_STORE__HOST: redis
jobs: jobs:
test: test:

View File

@@ -2,6 +2,8 @@ application:
port: 8080 port: 8080
host: "127.0.0.1" host: "127.0.0.1"
base_url: "http://127.0.0.1:8080" base_url: "http://127.0.0.1:8080"
email_client:
authorization_token: "secret-token"
database: database:
host: "127.0.0.1" host: "127.0.0.1"
port: 5432 port: 5432
@@ -10,6 +12,6 @@ database:
password: "password" password: "password"
require_ssl: false require_ssl: false
timeout_milliseconds: 1000 timeout_milliseconds: 1000
email_client: kv_store:
authorization_token: "secret-token" host: "127.0.0.1"
redis_uri: "redis://127.0.0.1:6379" port: 6379

View File

@@ -1,8 +1,13 @@
use crate::domain::SubscriberEmail; use crate::domain::SubscriberEmail;
use anyhow::Context;
use secrecy::{ExposeSecret, SecretString}; use secrecy::{ExposeSecret, SecretString};
use serde::Deserialize; use serde::Deserialize;
use serde_aux::field_attributes::deserialize_number_from_string; use serde_aux::field_attributes::deserialize_number_from_string;
use sqlx::postgres::{PgConnectOptions, PgSslMode}; use sqlx::postgres::{PgConnectOptions, PgSslMode};
use tower_sessions_redis_store::{
RedisStore,
fred::prelude::{ClientLike, Pool},
};
pub fn get_configuration() -> Result<Settings, config::ConfigError> { pub fn get_configuration() -> Result<Settings, config::ConfigError> {
let base_path = std::env::current_dir().expect("Failed to determine the current directory"); let base_path = std::env::current_dir().expect("Failed to determine the current directory");
@@ -60,7 +65,7 @@ pub struct Settings {
pub application: ApplicationSettings, pub application: ApplicationSettings,
pub database: DatabaseSettings, pub database: DatabaseSettings,
pub email_client: EmailClientSettings, pub email_client: EmailClientSettings,
pub redis_uri: SecretString, pub kv_store: RedisSettings,
} }
#[derive(Clone, Deserialize)] #[derive(Clone, Deserialize)]
@@ -100,6 +105,35 @@ impl EmailClientSettings {
} }
} }
#[derive(Clone, Deserialize)]
pub struct RedisSettings {
pub host: String,
pub port: u16,
}
impl RedisSettings {
pub fn connection_string(&self) -> String {
format!("redis://{}:{}", self.host, self.port)
}
pub async fn session_store(&self) -> Result<RedisStore<Pool>, anyhow::Error> {
let pool = Pool::new(
tower_sessions_redis_store::fred::prelude::Config::from_url(&self.connection_string())
.context("Failed to parse Redis URL string.")?,
None,
None,
None,
6,
)
.unwrap();
pool.connect();
pool.wait_for_connect()
.await
.context("Failed to connect to the Redis server.")?;
Ok(RedisStore::new(pool))
}
}
#[derive(Clone, Deserialize)] #[derive(Clone, Deserialize)]
pub struct DatabaseSettings { pub struct DatabaseSettings {
pub username: String, pub username: String,

View File

@@ -10,16 +10,12 @@ use axum::{
routing::{delete, get, post}, routing::{delete, get, post},
}; };
use reqwest::{StatusCode, header}; use reqwest::{StatusCode, header};
use secrecy::ExposeSecret;
use sqlx::{PgPool, postgres::PgPoolOptions}; use sqlx::{PgPool, postgres::PgPoolOptions};
use std::{sync::Arc, time::Duration}; use std::{sync::Arc, time::Duration};
use tokio::net::TcpListener; use tokio::net::TcpListener;
use tower_http::{services::ServeDir, trace::TraceLayer}; use tower_http::{services::ServeDir, trace::TraceLayer};
use tower_sessions::SessionManagerLayer; use tower_sessions::SessionManagerLayer;
use tower_sessions_redis_store::{ use tower_sessions_redis_store::{RedisStore, fred::prelude::Pool};
RedisStore,
fred::prelude::{ClientLike, Config, Pool},
};
use uuid::Uuid; use uuid::Uuid;
#[derive(Clone)] #[derive(Clone)]
@@ -46,18 +42,11 @@ impl Application {
)) ))
.connect_lazy_with(configuration.database.with_db()); .connect_lazy_with(configuration.database.with_db());
let email_client = EmailClient::build(configuration.email_client).unwrap(); let email_client = EmailClient::build(configuration.email_client).unwrap();
let pool = Pool::new( let redis_store = configuration
Config::from_url(configuration.redis_uri.expose_secret()) .kv_store
.expect("Failed to parse Redis URL string"), .session_store()
None, .await
None, .context("Failed to acquire Redis session store.")?;
None,
6,
)
.unwrap();
pool.connect();
pool.wait_for_connect().await.unwrap();
let redis_store = RedisStore::new(pool);
let router = app( let router = app(
connection_pool, connection_pool,
email_client, email_client,