< 返回版块

C-Jeril 发表于 2024-02-01 10:28

永远报错内容都是,只能硬编码或者直接命令行附上数据库的方法,不知道问题出在哪儿

Database URL: Err("environment variable not found")
error: process didn't exit successfully: `target\debug\backend.exe` (exit code: 1)


// src/main.rs
// 引入定义的路由模块和服务模块
mod db;
mod models;
mod routes;
mod schema;
mod service; // 引入db连接数据库模块

// 引入所需的库和模块External crate imports
use crate::db::establish_connection;
use log::error;
use std::env;
use std::net::SocketAddr;
use tokio::net::TcpListener;
use tracing::info;
use tracing_appender::rolling;
use tracing_subscriber::{EnvFilter, FmtSubscriber};
use dotenv;

// 主函数,启动异步运行时
#[tokio::main]
async fn main() {
    // 初始化log日志记录
    if let Ok(log_level) = env::var("LOG_LEVEL") {
        std::env::set_var("RUST_LOG", log_level);
    }
    dotenv::dotenv().ok();
    
    // 调用db.rs连接数据库
    let pool = match establish_connection() {
        Ok(pool) => pool,
        Err(e) => {
            error!("Failed to create database connection pool: {}", e);
            std::process::exit(1);
        }
    };

    // Create a new appender that rotates daily
    let file_appender = rolling::daily("log/directory", "prefix.log");
    // Create a non-blocking appender from the file appender
    let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);

    // 初始化日志订阅
    let subscriber = FmtSubscriber::builder()
        .with_writer(non_blocking)
        .with_env_filter(EnvFilter::from_default_env())
        .finish();

    // 确保日志文件夹存在,如果不存在,则创建它
    if std::fs::create_dir_all("log/directory").is_err() {
        error!("Failed to create log directory");
        return; // 或者处理错误
    }

    tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
    info!("程序启动");

    let app = routes::app_router(pool); // 使用 routes.rs 中定义的路由

    // 从环境变量中获取地址,如果没有设置,则使用默认地址
    let addr = match env::var("ADDRESS") {
        Ok(address) => address.parse::<SocketAddr>().unwrap_or_else(|_| {
            error!("Invalid ADDRESS format, using default");
            SocketAddr::from(([0, 0, 0, 0], 3000)) // 使用默认地址和端口
        }),
        Err(_) => {
            info!("No ADDRESS specified, using default");
            SocketAddr::from(([0, 0, 0, 0], 3000))
        }
    };
    println!("Server running at http://{}", addr); // 打印服务器运行地址
    println!("{:?}", std::env::current_dir()); // 打印当前工作目录的路径,确认它是否是你预期的目录。

    // 绑定服务器orTCP监听器到指定地址并启动服务
    let listener = match TcpListener::bind(&addr).await {
        Ok(listener) => listener,
        Err(e) => {
            error!("Failed to bind to {}: {}", addr, e);
            return; // 或者使用其他方式优雅地关闭程序
        }
    };

    // 使用axum的serve函数来处理连接
    match axum::serve(listener, app).await {
        Ok(_) => info!("Server stopped gracefully."),
        Err(e) => error!("Server error: {}", e),
    }
}
// src/db.rs
use diesel::pg::PgConnection;
use diesel::r2d2::{ConnectionManager, Pool, PoolError, PooledConnection};
use dotenv;
use http::StatusCode;
use log::{error, warn};
use std::env;
use std::error::Error;
use std::time::Duration;

// 为数据库连接池定义一个类型别名Type alias for the database pool
pub type DbPool = Pool<ConnectionManager<PgConnection>>;

pub fn establish_connection() -> Result<DbPool, Box<dyn Error>> {
    //   env::set_var("DATABASE_URL", "postgres://postgres:Cheng12345@localhost:5432/jscappdb");

    println!(
        "Database URL: {:?}",
        env::var("DATABASE_URL").map_err(|e| e.to_string())
    );

    let database_url = env::var("DATABASE_URL").map_err(|e| Box::new(e) as Box<dyn Error>)?;

    // 重试机制,用于在创建数据库连接池时处理失败的情况 Retry mechanism for establishing database connection
    let mut retries = 0;
    // 引入指数退避策略(Exponential Backoff)管理重试间隔,减少在高负载或暂时性问题时对数据库的冲击。
    let mut backoff = 1;

    while retries < 5 {
        let manager = ConnectionManager::<PgConnection>::new(&database_url);
        match Pool::builder()
            .max_size(15)
            .min_idle(Some(5))
            .connection_timeout(Duration::from_secs(30))
            .build(manager)
        {
            Ok(pool) => return Ok(pool),
            Err(e) => {
                warn!("Failed to create database connection pool: {}", e);
                warn!("Retrying in {} seconds...", backoff);
                std::thread::sleep(Duration::from_secs(backoff));
                retries += 1;
                backoff *= 2;
            }
        }
    }

    error!("Failed to establish database connection after retries");
    Err("Failed to establish database connection".into())
}

pub fn get_connection(
    pool: &DbPool,
) -> Result<PooledConnection<ConnectionManager<PgConnection>>, PoolError> {
    pool.get()
}

// 处理数据库连接错误并返回适当的错误信息
pub fn handle_db_error(e: Box<dyn Error>) -> (StatusCode, String) {
    error!("Database connection error: {}", e);
    (
        StatusCode::INTERNAL_SERVER_ERROR,
        "无法获取数据库连接".to_string(),
    )
}

# 数据库连接信息,指定数据库地址和凭据
DATABASE_URL="postgres://postgres:password@localhost:5432/db"
# 日志级别配置,指定为debug
LOG_LEVEL=debug
# 调试模式开关,指定为true
DEBUG_MODE=true
# 允许的CORS跨资源共享策略地址
ALLOWED_ORIGINS=http://localhost:5173
# 允许的微信应用ID,替换为您的微信应用ID
WECHAT_APP_ID=your_app_id
# 允许的微信应用密钥,替换为您的微信应用密钥
WECHAT_APP_SECRET=your_app_secret 
# 指定Rust日志级别
RUST_LOG=trace  
[dependencies]
axum = "^0.7.4"
tokio = { version = "^1", features = ["full"] }
diesel = { version = "^2.1.0", features = ["postgres", "r2d2", "chrono"] }
chrono = { version = "^0.4.31", features = ["serde"] }
r2d2 = "^0.8.10"
serde = { version = "^1.0", features = ["derive"] }
serde_json = "^1.0"
dotenv = "^0.15.0"
postgres = "^0.19.2"
http = "^0.2"
diesel-async = "^0.4.1"
r2d2_postgres = "^0.18.1"
log = "^0.4.20"
env_logger = "^0.10.1"
tower = { version = "^0.4.13", features = ["full"] }
tower-http = { version = "^0.5.1", features = ["full"] }
hyper = "^1.1.0"
server = "^0.1.0"
axum-util = "^0.2.2"
tracing = "^0.1.40"
axum-extra = { version = "^0.9.2", features = ["typed-header"] }
tokio-postgres-rustls = "^0.11.1"
tracing-subscriber = { version = "^0.3.18", features = ["env-filter", "fmt"] }
tracing-appender = "^0.2.3"
jsonwebtoken = "^9.2.0"
bcrypt = "^0.15.0"
headers = "0.4.0"

评论区

写评论
作者 C-Jeril 2024-02-02 09:31
called `Result::unwrap()` on an `Err` value: Io(Error { kind: InvalidData, message: "stream did not contain valid UTF-8" })
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

目前发现应该是env文件里有其他数据,尝试把中文注释也全部去掉了,重新用程序生成了一个env文件; 现在运行基本顺畅多了,但还需要多次运行,很容易提示exit code: 3,怀疑是被占用导致的,因为多次运行后还是会顺畅运行。

error: process didn't exit successfully: `target\debug\backend.exe` (exit code: 3)

--
👇
Bai-Jinlin: 感觉你定位错误和提问的能力该加强下了。你这个代码出问题应该最先想到把dotenv::dotenv().ok()改成dotenv::dotenv().unwrap();看看是不是这里出问题了吧?

作者 C-Jeril 2024-02-02 08:55

.env一直放在后端项目的根目录下,的确是在同一个目录,甚至放到src下我都试过,就是没生效。

--
👇
wangzk1900: 先加载.env文件:dotenv::dotenv().ok()

再获取变量:env::var("LOG_LEVEL")

另外,.env应该和src在同一目录下。

作者 C-Jeril 2024-02-02 08:54

嗯嗯,的确是在需要加强,感谢感谢🙏 您说的尝试过,但是没有找出问题。

--
👇
Bai-Jinlin: 感觉你定位错误和提问的能力该加强下了。你这个代码出问题应该最先想到把dotenv::dotenv().ok()改成dotenv::dotenv().unwrap();看看是不是这里出问题了吧?

作者 C-Jeril 2024-02-02 08:53

.env

--
👇
bestgopher: 环境变量文件名叫啥?

wangzk1900 2024-02-01 15:45

先加载.env文件:dotenv::dotenv().ok()

再获取变量:env::var("LOG_LEVEL")

另外,.env应该和src在同一目录下。

Bai-Jinlin 2024-02-01 11:18

感觉你定位错误和提问的能力该加强下了。你这个代码出问题应该最先想到把dotenv::dotenv().ok()改成dotenv::dotenv().unwrap();看看是不是这里出问题了吧?

bestgopher 2024-02-01 10:34

环境变量文件名叫啥?

1 共 7 条评论, 1 页