From 329fd5b86c25e11c1e76f2cdeaa53b3044b676c4 Mon Sep 17 00:00:00 2001 From: Andre Heber Date: Mon, 19 Feb 2024 17:49:19 +0100 Subject: [PATCH] build pipeline, health check works again --- ...db11a68a6d4d3b689d75140a4c74d8b9f59e4.json | 17 +++++ Dockerfile | 11 +++ configuration.yaml => configuration/base.yaml | 3 +- configuration/development.yaml | 2 + configuration/production.yaml | 2 + src/configuration.rs | 76 ++++++++++++++----- src/main.rs | 4 +- 7 files changed, 95 insertions(+), 20 deletions(-) create mode 100644 .sqlx/query-eab54567b7111647243528e961fdb11a68a6d4d3b689d75140a4c74d8b9f59e4.json create mode 100644 Dockerfile rename configuration.yaml => configuration/base.yaml (82%) create mode 100644 configuration/development.yaml create mode 100644 configuration/production.yaml diff --git a/.sqlx/query-eab54567b7111647243528e961fdb11a68a6d4d3b689d75140a4c74d8b9f59e4.json b/.sqlx/query-eab54567b7111647243528e961fdb11a68a6d4d3b689d75140a4c74d8b9f59e4.json new file mode 100644 index 0000000..07382ef --- /dev/null +++ b/.sqlx/query-eab54567b7111647243528e961fdb11a68a6d4d3b689d75140a4c74d8b9f59e4.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n\t\tINSERT INTO subscriptions (id, email, name, subscribed_at)\n\t\tVALUES ($1, $2, $3, $4)\n\t\t", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Text", + "Text", + "Timestamptz" + ] + }, + "nullable": [] + }, + "hash": "eab54567b7111647243528e961fdb11a68a6d4d3b689d75140a4c74d8b9f59e4" +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8e69287 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM rust:1.76.0 + +WORKDIR /app + +RUN apt update && apt install lld clang -y +COPY . . +ENV SQLX_OFFLINE true +RUN cargo build --release +ENV APP_ENVIRONMENT production + +ENTRYPOINT ["./target/release/zero2prod"] diff --git a/configuration.yaml b/configuration/base.yaml similarity index 82% rename from configuration.yaml rename to configuration/base.yaml index 85a79ac..f16313b 100644 --- a/configuration.yaml +++ b/configuration/base.yaml @@ -1,4 +1,5 @@ -application_port: 8000 +application: + port: 8000 database: host: "127.0.0.1" port: 5432 diff --git a/configuration/development.yaml b/configuration/development.yaml new file mode 100644 index 0000000..c464c2f --- /dev/null +++ b/configuration/development.yaml @@ -0,0 +1,2 @@ +application: + host: 127.0.0.1 diff --git a/configuration/production.yaml b/configuration/production.yaml new file mode 100644 index 0000000..b936a88 --- /dev/null +++ b/configuration/production.yaml @@ -0,0 +1,2 @@ +application: + host: 0.0.0.0 diff --git a/src/configuration.rs b/src/configuration.rs index 01dac62..cfbb890 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -3,26 +3,32 @@ use secrecy::{ExposeSecret, Secret}; #[derive(serde::Deserialize)] pub struct Settings { - pub database: DatabaseSettings, - pub application_port: u16, + pub database: DatabaseSettings, + pub application: ApplicationSettings, +} + +#[derive(serde::Deserialize)] +pub struct ApplicationSettings { + pub port: u16, + pub host: String, } #[derive(serde::Deserialize)] pub struct DatabaseSettings { - pub username: String, - pub password: Secret, - pub port: u16, - pub host: String, - pub database_name: String, + pub username: String, + pub password: Secret, + pub port: u16, + pub host: String, + pub database_name: String, } impl DatabaseSettings { - pub fn connection_string(&self) -> Secret { - Secret::new(format!( - "postgres://{}:{}@{}:{}/{}", - self.username, self.password.expose_secret(), self.host, self.port, self.database_name - )) - } + pub fn connection_string(&self) -> Secret { + Secret::new(format!( + "postgres://{}:{}@{}:{}/{}", + self.username, self.password.expose_secret(), self.host, self.port, self.database_name + )) + } pub fn connection_string_without_db(&self) -> Secret { Secret::new(format!( @@ -33,9 +39,45 @@ impl DatabaseSettings { } pub fn get_configuration() -> Result { - let settings = Config::builder() - .add_source(config::File::with_name("configuration")) - .build()?; + let run_mode = std::env::var("APP_ENVIRONMENT").unwrap_or("development".into()); + let base_path = std::env::current_dir().expect("Failed to determine the current directory"); + let configuration_directory = base_path.join("configuration"); // "./configuration" - settings.try_deserialize() + let base_config_file = configuration_directory.join("base"); // "./configuration/base" + let base_config_file = base_config_file.to_str().expect("Invalid base config file path"); + let environment_config_file = configuration_directory.join(run_mode.to_lowercase()); // "./configuration/[development/production]" + let environment_config_file = environment_config_file.to_str().expect("Invalid environment config file path"); + + let settings = Config::builder() + .add_source(config::File::with_name(base_config_file).required(true)) + .add_source(config::File::with_name(environment_config_file).required(true)) + .build()?; + + settings.try_deserialize() } + +pub enum Environment { + Development, + Production, +} + +impl Environment { + pub fn as_str(&self) -> &'static str { + match self { + Environment::Development => "development", + Environment::Production => "production", + } + } +} + +impl TryFrom for Environment { + type Error = String; + + fn try_from(s: String) -> Result { + match s.to_lowercase().as_str() { + "development" => Ok(Environment::Development), + "production" => Ok(Environment::Production), + _ => Err(format!("{} is not a valid environment", s)), + } + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index d0425a1..591129c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,9 +12,9 @@ async fn main() -> std::io::Result<()> { let config = get_configuration().expect("Failed to read configuration"); let connection_pool = PgPoolOptions::new() - .max_connections(10).connect(config.database.connection_string().expose_secret()).await.expect("Failed to connect to Postgres."); + .max_connections(10).connect_lazy(config.database.connection_string().expose_secret()).expect("Failed to connect to Postgres."); - let address = format!("127.0.0.1:{}", config.application_port); + let address = format!("{}:{}", config.application.host, config.application.port); let listener = TcpListener::bind(address).expect("Failed to bind random port"); run(listener, connection_pool)?.await }