forked from boos/BoosAPI
feat: add workflow studio and postgres support
This commit is contained in:
+40
-24
@@ -1,7 +1,7 @@
|
||||
use anyhow::Context;
|
||||
use axum::serve;
|
||||
use boosapi::{config::AppConfig, db, services::builtin_keys, AppState};
|
||||
use clap::Parser;
|
||||
use clap::{Parser, Subcommand};
|
||||
use std::ffi::OsString;
|
||||
use std::net::SocketAddr;
|
||||
use tokio::signal;
|
||||
@@ -15,6 +15,9 @@ use tracing_subscriber::EnvFilter;
|
||||
about = "AI API Gateway — Rust rewrite of BoosAPI"
|
||||
)]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: Option<Commands>,
|
||||
|
||||
/// Config file path
|
||||
#[arg(short, long, default_value = "config.toml")]
|
||||
config: String,
|
||||
@@ -40,10 +43,42 @@ struct Cli {
|
||||
check_config: bool,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum Commands {
|
||||
/// Copy core data from SQLite into PostgreSQL and exit
|
||||
MigrateSqliteToPostgres {
|
||||
/// Source SQLite URL, e.g. sqlite:boosapi.db?mode=rwc
|
||||
#[arg(long)]
|
||||
sqlite_url: String,
|
||||
|
||||
/// Target PostgreSQL URL, e.g. postgres://user:pass@host:5432/boosapi
|
||||
#[arg(long)]
|
||||
postgres_url: String,
|
||||
|
||||
/// Truncate target business tables before importing
|
||||
#[arg(long)]
|
||||
force_truncate: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let args = Cli::parse_from(normalize_legacy_args());
|
||||
|
||||
if let Some(Commands::MigrateSqliteToPostgres {
|
||||
sqlite_url,
|
||||
postgres_url,
|
||||
force_truncate,
|
||||
}) = &args.command
|
||||
{
|
||||
let sqlite = db::create_pool(sqlite_url, 1).await?;
|
||||
let pg = db::create_pg_pool(postgres_url, 2).await?;
|
||||
db::run_migrations(db::DbKind::Postgres, None, Some(&pg)).await?;
|
||||
let summary = db::sqlite_to_postgres::migrate(&sqlite, &pg, *force_truncate).await?;
|
||||
println!("{}", serde_json::to_string_pretty(&summary)?);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Load config
|
||||
let mut config = AppConfig::load_from_file(&args.config)?;
|
||||
|
||||
@@ -73,12 +108,14 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
tracing::info!("Loaded configuration from {}", args.config);
|
||||
|
||||
let db_kind = db::DbKind::from_url(&config.db.url)?;
|
||||
|
||||
// Create database pool
|
||||
let pool = db::create_pool(&config.db.url, config.db.max_connections).await?;
|
||||
tracing::info!("Database connected");
|
||||
|
||||
// Run migrations
|
||||
sqlx::migrate!("./migrations").run(&pool).await?;
|
||||
db::run_migrations(db_kind, Some(&pool), None).await?;
|
||||
tracing::info!("Database migrations applied");
|
||||
|
||||
if args.migrate_only {
|
||||
@@ -105,20 +142,6 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
let comfyui_process = state.comfyui.clone();
|
||||
|
||||
// Multi-tenant ComfyUI pool: adopt any containers that survived a
|
||||
// previous API restart, then start the idle-reaper task. Only
|
||||
// wired in when the `multi_tenant_comfy` feature is on; under the
|
||||
// legacy singleton path the pool is constructed but unused, and
|
||||
// `comfyui_pool` is `None` so we skip shutdown_all on exit.
|
||||
#[cfg(feature = "multi_tenant_comfy")]
|
||||
let comfyui_pool = {
|
||||
state.comfyui_pool.reconcile_on_startup().await;
|
||||
boosapi::services::comfyui_pool::spawn_reaper(state.comfyui_pool.clone());
|
||||
Some(state.comfyui_pool.clone())
|
||||
};
|
||||
#[cfg(not(feature = "multi_tenant_comfy"))]
|
||||
let comfyui_pool: Option<std::sync::Arc<boosapi::services::comfyui_pool::ComfyUIPool>> = None;
|
||||
|
||||
// Build router
|
||||
let app = boosapi::routes::build_router(state);
|
||||
|
||||
@@ -128,7 +151,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
serve(
|
||||
tokio::net::TcpListener::bind(addr).await?,
|
||||
app.into_make_service(),
|
||||
app.into_make_service_with_connect_info::<SocketAddr>(),
|
||||
)
|
||||
.with_graceful_shutdown(shutdown_signal())
|
||||
.await?;
|
||||
@@ -137,13 +160,6 @@ async fn main() -> anyhow::Result<()> {
|
||||
tracing::warn!(%err, "ComfyUI embedded process did not stop cleanly");
|
||||
}
|
||||
|
||||
// Tear down any per-user ComfyUI containers we spawned. This is
|
||||
// best-effort — a hard kill of the API leaves them running and the
|
||||
// next startup will adopt them via reconcile_on_startup().
|
||||
if let Some(pool) = comfyui_pool {
|
||||
pool.shutdown_all().await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user