From d19a9c357716df2948c2ffd00914b0e8ead21186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Mi=C5=82ek?= Date: Sun, 8 Dec 2024 18:15:24 +0100 Subject: [PATCH] 232: Set up env switching and write instructions --- backend/.gitignore | 1 + backend/README.md | 85 +++++++++++++++++++++++++++++++++++++++--- backend/src/main.rs | 11 +++--- backend/src/startup.rs | 25 +++++++++++++ 4 files changed, 110 insertions(+), 12 deletions(-) diff --git a/backend/.gitignore b/backend/.gitignore index c9b8d5d1..720d5ab7 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,5 +1,6 @@ # Environment variables .env +.env.prod # Generated by Cargo # will have compiled files and executables diff --git a/backend/README.md b/backend/README.md index b549388c..f03c3957 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,31 +1,104 @@ # RMoods Backend ## Build + For deployment, append the `release` flag. + ```sh cargo build ``` - ## Run + +To run in debug mode, using the `.env` file: + ```sh cargo run ``` -### Environment -Your `.env` file should look like this: + +To run in release mode, using the `.env.prod` file, just add the `--release` flag. +**Be careful! Using the production DB for development is forbidden** + +```sh +cargo run --release +``` + +## Local Environment + +Your `.env` file should have all the properties as listed in the `.env.example` file. +Don't worry, the server verifies the presence of these variables at startup. + +[Docker Desktop](https://www.docker.com/products/docker-desktop/) is recommended, as it's really easy to manage +containers there. + +### Database setup + +You'll need a local PostgreSQL database to run the backend and not cause any trouble with the production DB. + +First, download the image that matches our production database version. + +```sh +docker pull postgres:15.10 +``` + +Create a docker volume to persist the data between container runs. + +```sh +docker volume create rmoods-dev-pgdata +``` + +Run the container with the volume mounted. + +```sh +docker run --name rmoods-dev-db -p 8003:5432 -e POSTGRES_USER=rmoods-dev -e POSTGRES_PASSWORD=mypasswd -e POSTGRES_DB=rmoods -v rmoods-dev-pgdata:/var/lib/postgresql/data postgres:15.10 +``` + +Add this to your `.env` file: + +```sh +DATABASE_URL=postgres://rmoods-dev:mypasswd@localhost:8003/rmoods-db ``` -CLIENT_ID=*** -CLIENT_SECRET=*** -DATABASE_URL=*** + +The production DB URL is kept only in `.env.prod`. + +To restart the container afterward: + +```sh +docker start rmoods-dev-db --attach ``` +With that, you should have a local database running. Now you need to configure it to match our backend code and data +schema. + +### SQLx CLI + +To maintain your local database, you need to use the `sqlx` CLI tool from time to time. +Refer to the [SQLx CLI documentation](https://github.com/launchbadge/sqlx/blob/main/sqlx-cli/README.md). +Just to get you started: + +```sh +sqlx database create +sqlx migrate run +``` + +Whenever we change the schema, you need to keep the local DB in sync. You can just drop the database and recreate it. + +```sh +sqlx database drop +sqlx database create +sqlx migrate run +``` ## Docker + Backend for RMoods can be run a Docker container. + ```Dockerfile docker build -t rmoods-backend . ``` + After it's done building, run the container. You may want to map the default 8001 port to 9001 for differentiation. + ```Dockerfile docker run -p 9001:8001 rmoods-backend ``` diff --git a/backend/src/main.rs b/backend/src/main.rs index d6817f5c..eabc903d 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -1,8 +1,9 @@ +use crate::env::DATABASE_URL; use crate::fetcher::fetcher::RMoodsFetcher; use crate::fetcher::reddit::connection::RedditConnection; use crate::nlp::nlp_client::NlpClient; use crate::open_api::ApiDoc; -use crate::startup::{shutdown_signal, verify_environment}; +use crate::startup::{setup_environment, shutdown_signal, verify_environment}; use crate::websocket::SystemMessage; use axum::Router; use log::{error, info, warn}; @@ -42,7 +43,7 @@ pub struct AppState { /// Run the server, assuming the environment has been already validated. async fn run() -> anyhow::Result<()> { - let url = std::env::var("DATABASE_URL").expect("DB_URL is set"); + let url = std::env::var(DATABASE_URL).expect("DB_URL is set"); let pool = PgPoolOptions::new() .max_connections(10) .connect(&url) @@ -113,16 +114,14 @@ async fn run() -> anyhow::Result<()> { } /// Entry point of the RMoods server. -/// Validates the environment, initializes the server and runs it. +/// Sets up and validates the environment, initializes the server and runs it. #[tokio::main] async fn main() { std::env::set_var("RUST_LOG", "debug"); std::env::set_var("RUST_BACKTRACE", "0"); env_logger::init(); - if dotenvy::dotenv().is_err() { - warn!(".env not found. Environment variables will have to be defined outside of .env"); - } + setup_environment(); if !verify_environment() { error!("Invalid environment, aborting."); diff --git a/backend/src/startup.rs b/backend/src/startup.rs index fbb4e8f5..8cf3603e 100644 --- a/backend/src/startup.rs +++ b/backend/src/startup.rs @@ -28,6 +28,31 @@ pub fn verify_environment() -> bool { is_ok } +/// Sets up the environment for the application. +/// If we're in debug mode, we load the .env file. +/// Otherwise, we expect all environment variables to be defined. +pub fn setup_environment() { + #[cfg(debug_assertions)] + { + log::warn!("Running in debug mode."); + if dotenvy::dotenv().is_err() { + log::warn!( + "Failed to load .env file. Environment variables will have to be defined outside" + ); + } + } + + #[cfg(not(debug_assertions))] + { + log::warn!("Running in production mode."); + if dotenvy::from_filename_override(".env.prod").is_err() { + log::warn!( + "Failed to load .env.prod file. Environment variables will have to be defined outside" + ); + } + } +} + pub async fn shutdown_signal(cancellation_token: CancellationToken) { let ctrl_c = async { signal::ctrl_c()