永远报错内容都是,只能硬编码或者直接命令行附上数据库的方法,不知道问题出在哪儿
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"
1
共 7 条评论, 1 页
评论区
写评论目前发现应该是env文件里有其他数据,尝试把中文注释也全部去掉了,重新用程序生成了一个env文件; 现在运行基本顺畅多了,但还需要多次运行,很容易提示exit code: 3,怀疑是被占用导致的,因为多次运行后还是会顺畅运行。
--
👇
Bai-Jinlin: 感觉你定位错误和提问的能力该加强下了。你这个代码出问题应该最先想到把dotenv::dotenv().ok()改成dotenv::dotenv().unwrap();看看是不是这里出问题了吧?
.env一直放在后端项目的根目录下,的确是在同一个目录,甚至放到src下我都试过,就是没生效。
--
👇
wangzk1900: 先加载
.env
文件:dotenv::dotenv().ok()
再获取变量:
env::var("LOG_LEVEL")
另外,
.env
应该和src
在同一目录下。嗯嗯,的确是在需要加强,感谢感谢🙏 您说的尝试过,但是没有找出问题。
--
👇
Bai-Jinlin: 感觉你定位错误和提问的能力该加强下了。你这个代码出问题应该最先想到把dotenv::dotenv().ok()改成dotenv::dotenv().unwrap();看看是不是这里出问题了吧?
.env
--
👇
bestgopher: 环境变量文件名叫啥?
先加载
.env
文件:dotenv::dotenv().ok()
再获取变量:
env::var("LOG_LEVEL")
另外,
.env
应该和src
在同一目录下。感觉你定位错误和提问的能力该加强下了。你这个代码出问题应该最先想到把dotenv::dotenv().ok()改成dotenv::dotenv().unwrap();看看是不是这里出问题了吧?
环境变量文件名叫啥?