Skip to content

Commit d17fecc

Browse files
committed
chore: production environment deployed and tested
1 parent 4fc8c78 commit d17fecc

File tree

6 files changed

+79
-27
lines changed

6 files changed

+79
-27
lines changed

Diff for: Dockerfile

+2
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,7 @@ ENV SQLX_OFFLINE true
1313
# Let's build our binary!
1414
# We'll use the release profile to make it faaaast
1515
RUN cargo build --release
16+
# Instruct the binary in our Docker image to use the production configuration
17+
ENV APP_ENVIRONMENT production
1618
# When `docker run` is executed, launch the
1719
ENTRYPOINT ["./target/release/robust-rust"]

Diff for: configuration.yaml

-7
This file was deleted.

Diff for: src/configuration.rs

+62-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
use secrecy::{Secret, ExposeSecret};
1+
use secrecy::{ExposeSecret, Secret};
22

33
#[derive(serde::Deserialize)]
44
pub struct Settings {
55
pub database: DatabaseSettings,
6-
pub application_port: u16,
6+
pub application: ApplicationSettings,
7+
}
8+
9+
#[derive(serde::Deserialize)]
10+
pub struct ApplicationSettings {
11+
pub port: u16,
12+
pub host: String,
713
}
814

915
#[derive(serde::Deserialize)]
@@ -19,25 +25,72 @@ impl DatabaseSettings {
1925
pub fn connection_string(&self) -> Secret<String> {
2026
Secret::new(format!(
2127
"postgres://{}:{}@{}:{}/{}",
22-
self.username, self.password.expose_secret(), self.host, self.port, self.database_name
28+
self.username,
29+
self.password.expose_secret(),
30+
self.host,
31+
self.port,
32+
self.database_name
2333
))
2434
}
2535

2636
pub fn connection_string_without_db(&self) -> Secret<String> {
2737
Secret::new(format!(
2838
"postgres://{}:{}@{}:{}",
29-
self.username, self.password.expose_secret(), self.host, self.port
39+
self.username,
40+
self.password.expose_secret(),
41+
self.host,
42+
self.port
3043
))
3144
}
3245
}
3346

3447
pub fn get_configuration() -> Result<Settings, config::ConfigError> {
3548
// Initialize our configuration reader
3649
let mut settings = config::Config::default();
37-
// Add configuration values from a file named `configuration`
38-
// with the `ini` file format
39-
settings.merge(config::File::with_name("configuration"))?;
40-
// Try to convert the configuration values it read into
41-
// our Settings type
50+
let base_path = std::env::current_dir().expect("Failed to determine the current directory");
51+
let configuration_directory = base_path.join("configuration");
52+
53+
// Read the "default" configuration file
54+
settings.merge(config::File::from(configuration_directory.join("base")).required(true))?;
55+
56+
// Detect the running environment
57+
// Default to 'local' if unspecified
58+
let environment: Environment = std::env::var("APP_ENVIRONMENT")
59+
.unwrap_or_else(|_| "local".into())
60+
.try_into()
61+
.expect("APP_ENVIRONMENT must be 'local' or 'production'");
62+
63+
// Layer on environment specific values
64+
settings.merge(
65+
config::File::from(configuration_directory.join(environment.as_str())).required(true)
66+
)?;
67+
4268
settings.try_into()
4369
}
70+
71+
// The possible runtime environment for our application
72+
// We can run our application in either "local" or "production" mode
73+
pub enum Environment {
74+
Local,
75+
Production,
76+
}
77+
78+
impl Environment {
79+
pub fn as_str(&self) -> &str {
80+
match self {
81+
Environment::Local => "local",
82+
Environment::Production => "production",
83+
}
84+
}
85+
}
86+
87+
impl TryFrom<String> for Environment {
88+
type Error = String;
89+
fn try_from(value: String) -> Result<Self, Self::Error> {
90+
match value.to_lowercase().as_str() {
91+
"local" => Ok(Self::Local),
92+
"production" => Ok(Self::Production),
93+
_ => Err(format!("{} is not a supported environment. Use either local or production", value)),
94+
}
95+
}
96+
}

Diff for: src/main.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
use robust_rust::configuration::get_configuration;
22
use robust_rust::startup::run;
33
use robust_rust::telemetry::{get_subscriber, init_subscriber};
4+
use secrecy::ExposeSecret;
45
use sqlx::PgPool;
56
use std::net::TcpListener;
6-
use secrecy::ExposeSecret;
77

88
#[tokio::main]
99
async fn main() -> std::io::Result<()> {
1010
let subscriber = get_subscriber("robust_rust".into(), "info".into(), std::io::stdout);
1111
init_subscriber(subscriber);
1212
let configuration = get_configuration().expect("Failed to read configuration.");
13-
let connection_pool = PgPool::connect(configuration.database.connection_string().expose_secret())
14-
.await
15-
.expect("Failed to connect to Postgres.");
16-
let address = format!("127.0.0.1:{}", configuration.application_port);
13+
let connection_pool =
14+
PgPool::connect_lazy(configuration.database.connection_string().expose_secret())
15+
.expect("Failed to connect to Postgres.");
16+
let address = format!(
17+
"{}:{}",
18+
configuration.application.host, configuration.application.port
19+
);
1720
let listener = TcpListener::bind(address).expect("Failed to bind random port");
1821
run(listener, connection_pool)?.await?;
1922
Ok(())

Diff for: src/routes/subscriptions.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use actix_web::{web, HttpResponse};
22
use chrono::Utc;
3-
use sqlx::PgPool;
43
use sqlx::types::Uuid;
4+
use sqlx::PgPool;
55
// use uuid::Uuid;
66

77
#[allow(dead_code)]
@@ -32,7 +32,7 @@ pub async fn subscribe(form: web::Form<FormData>, pool: web::Data<PgPool>) -> Ht
3232

3333
#[tracing::instrument(
3434
name = "Saving a new subscriber details in the database",
35-
skip(form, pool),
35+
skip(form, pool)
3636
)]
3737
async fn insert_subscriber(form: &FormData, pool: &PgPool) -> Result<(), sqlx::Error> {
3838
let subscribe_id = Uuid::new_v4();

Diff for: tests/health_check.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ use robust_rust::{
55
startup::run,
66
telemetry::{get_subscriber, init_subscriber},
77
};
8+
use secrecy::ExposeSecret;
89
use sqlx::{Connection, Executor, PgConnection, PgPool};
910
use std::net::TcpListener;
1011
use uuid::Uuid;
11-
use secrecy::ExposeSecret;
1212

1313
// Ensure that the `tracing` stack is only initialized once using `Lazy`.
1414
static TRACING: Lazy<()> = Lazy::new(|| {
@@ -55,9 +55,10 @@ async fn spawn_app() -> TestApp {
5555

5656
pub async fn configure_database(config: &DatabaseSettings) -> PgPool {
5757
// Create database
58-
let mut connection = PgConnection::connect(config.connection_string_without_db().expose_secret())
59-
.await
60-
.expect("Failed to connect to Postgres");
58+
let mut connection =
59+
PgConnection::connect(config.connection_string_without_db().expose_secret())
60+
.await
61+
.expect("Failed to connect to Postgres");
6162
connection
6263
.execute(format!(r#"CREATE DATABASE "{}";"#, config.database_name).as_str())
6364
.await

0 commit comments

Comments
 (0)