runtara-core 1.6.4

Core execution engine for runtara - manages instances, checkpoints, signals, and durable sleep
Documentation
// Copyright (C) 2025 SyncMyOrders Sp. z o.o.
// SPDX-License-Identifier: AGPL-3.0-or-later
//! Runtara Core - Durable Execution Engine
//!
//! Core is responsible for:
//! - Checkpoints (save/restore durable state)
//! - Signals (deliver to instances)
//! - Instance events (audit log)
//!
//! Note: Image registry, instance launching, and container management
//! are handled by runtara-environment.

use std::sync::Arc;

use anyhow::Result;
use sqlx::postgres::PgPoolOptions;
use sqlx::sqlite::SqlitePoolOptions;
use tracing::{error, info};

use runtara_core::config::Config;
use runtara_core::persistence::{Persistence, PostgresPersistence, SqlitePersistence};
use runtara_core::runtime::CoreRuntime;

#[tokio::main]
async fn main() -> Result<()> {
    // Load .env file (from crate directory or parent directories)
    dotenvy::dotenv().ok();

    // Initialize tracing
    tracing_subscriber::fmt()
        .with_env_filter(
            tracing_subscriber::EnvFilter::from_default_env()
                .add_directive("runtara_core=info".parse().unwrap()),
        )
        .init();

    info!("Starting Runtara Core");

    // Load configuration
    let config = Config::from_env().map_err(|e| {
        error!("Configuration error: {}", e);
        e
    })?;

    info!(
        instance_addr = %config.http_addr,
        max_instances = config.max_concurrent_instances,
        "Configuration loaded"
    );

    // Connect to database (Postgres or SQLite)
    info!("Connecting to database...");
    let persistence: Arc<dyn Persistence> = if config.database_url.starts_with("postgres://")
        || config.database_url.starts_with("postgresql://")
    {
        let pool = PgPoolOptions::new()
            .max_connections(10)
            .connect(&config.database_url)
            .await?;

        info!("Database connection established (Postgres)");

        // Verify connection
        let row: (i32,) = sqlx::query_as("SELECT 1").fetch_one(&pool).await?;
        info!(result = row.0, "Database health check passed");

        info!("Running database migrations...");
        runtara_core::migrations::run_postgres(&pool).await?;
        info!("Migrations completed");

        Arc::new(PostgresPersistence::new(pool))
    } else {
        let pool = SqlitePoolOptions::new()
            .max_connections(10)
            .connect(&config.database_url)
            .await?;

        info!("Database connection established (SQLite)");

        info!("Running database migrations...");
        runtara_core::migrations::run_sqlite(&pool).await?;
        info!("Migrations completed");

        Arc::new(SqlitePersistence::new(pool))
    };

    // Start the runtime
    let runtime = CoreRuntime::builder()
        .persistence(persistence)
        .bind_addr(config.http_addr)
        .build()?
        .start()
        .await?;

    info!(addr = %config.http_addr, "Runtara Core ready");

    // Wait for shutdown signal
    tokio::signal::ctrl_c().await?;
    info!("Shutting down...");

    // Graceful shutdown
    runtime.shutdown().await?;

    Ok(())
}