Rust wont set env variable?

so i'm using Salvo.rs and Sqlx to create a web frontend for BORG Backup, and i'm running into a problem.

This is the code:

// MAIN PROGRAM
#[tokio::main]
pub async fn main() {
    // general variables        
        let dbkey = "DATABASE_URL";
        let dbvalue = "postgres://user:password@host/database";
        env::set_var(dbkey, dbvalue);
        let pool = PgPool::connect(&dbvalue).await.unwrap();
        POSTGRES.set(pool).unwrap();
    tracing_subscriber::fmt().init();
    tracing::info!("Listening on http://0.0.0.0:7878");
    Server::new(TcpListener::bind("0.0.0.0:7878")).serve(routes()).await;
}

But the program panics. when i set DATABASE_URL using an .env file, it works.
idealy i would use the ini crate to get the database info from an ini file, and this works. but sqlx complains that the DATABASE_URL env variable needs to be set before it can use the query macro. If someone knows a wy around that then thats also a solution. I've read the documentation for std::env and sqlx, but this one problem i seem to be unable to solve. i tried making the variables a string, a &str, i tried to add .to_string(), etc etc.

The sqlx::query documentation says:

The DATABASE_URL environment variable must be set at build-time ...

env::set_var() is called at runtime, not build time.

In other words, DATABASE_URL='...' cargo build will compile the ... directly into the binary, and it will persist across any number of cargo run sessions (until it needs to rebuild).

Also according to the docs, you should probably be using a static .env file instead of trying to rewrite the environment at startup.

It's unsound to call set_var when more than one thread is running. If you can not call it at all, that's probably best. If you need to call it, call it in a vanilla main before there's a runtime (and before doing anything else that might spawn a thread).

2 Likes

Thanks everyone for responding :slight_smile: idealy i would not use the environment variable at all. i have a settings.ini that contains the database settings. However, this function requires the env:

// ADD DATA TO DATABASE
#[handler]
pub async fn borg_postlogs(res: &mut Response, req: &mut Request) {
    // POST incoming data to the database
    let d = req.parse_json::<Data>().await.unwrap();
    let query = sqlx::query!(
    "INSERT INTO borglogs (token, date, name, hostname, duration, files, compressed_size, original_size, repository_id, backupdir) 
    VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
    d.token, d.date, d.name, d.hostname, d.duration, d.files, d.compressed_size, d.original_size, d.repository_id, d.backupdir
    )
    .execute(get_postgres())

i am looking into using query_as but im not sure if that can work as well.

At this point im even willing to switch something else :slight_smile: i looked into an ORM but i think this adds too much stuff i dont use.

No, it will not. It will use the DATABASE_URL to check your queries against the schema of that database.
You're free to configure a different database at runtime of course.
You can also build in "offline-mode", requiring the database connection only to check the queries against the schema and then dump that information into a file (which can also be checked in), see the docs about it.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.