Fundamental_Analysis/services/report-generator-service/src/message_consumer.rs
Lv, Qi 427776b863 feat(analysis): Implement Configurable Analysis Template Engine
This commit introduces a comprehensive, template-based analysis orchestration system, refactoring the entire analysis generation workflow from the ground up.

Key Changes:

1.  **Backend Architecture (`report-generator-service`):**
    *   Replaced the naive analysis workflow with a robust orchestrator based on a Directed Acyclic Graph (DAG) of module dependencies.
    *   Implemented a full topological sort (`petgraph`) to determine the correct execution order and detect circular dependencies.

2.  **Data Models (`common-contracts`, `data-persistence-service`):**
    *   Introduced the concept of `AnalysisTemplateSets` to allow for multiple, independent, and configurable analysis workflows.
    *   Created a new `analysis_results` table to persist the output of each module for every analysis run, ensuring traceability.
    *   Implemented a file-free data seeding mechanism to populate default analysis templates on service startup.

3.  **API Layer (`api-gateway`):**
    *   Added a new asynchronous endpoint (`POST /analysis-requests/{symbol}`) to trigger analysis workflows via NATS messages.
    *   Updated all configuration endpoints to support the new `AnalysisTemplateSets` model.

4.  **Frontend UI (`/config`, `/query`):**
    *   Completely refactored the "Analysis Config" page into a two-level management UI for "Template Sets" and the "Modules" within them, supporting full CRUD operations.
    *   Updated the "Query" page to allow users to select which analysis template to use when generating a report.

This new architecture provides a powerful, flexible, and robust foundation for all future development of our intelligent analysis capabilities.
2025-11-18 07:47:08 +08:00

45 lines
1.5 KiB
Rust

use std::sync::Arc;
use common_contracts::messages::GenerateReportCommand;
use futures::StreamExt;
use tracing::{error, info};
use crate::{state::AppState, worker::run_report_generation_workflow};
const SUBJECT_NAME: &str = "analysis.commands.generate_report";
pub async fn subscribe_to_commands(
app_state: AppState,
nats_client: async_nats::Client,
) -> Result<(), anyhow::Error> {
let mut subscriber = nats_client.subscribe(SUBJECT_NAME.to_string()).await?;
info!(
"Consumer started, waiting for commands on subject '{}'",
SUBJECT_NAME
);
while let Some(message) = subscriber.next().await {
info!("Received NATS command to generate report.");
let state_clone = app_state.clone();
tokio::spawn(async move {
match serde_json::from_slice::<GenerateReportCommand>(&message.payload) {
Ok(command) => {
info!(
"Deserialized command for symbol: {}, template: {}",
command.symbol, command.template_id
);
if let Err(e) = run_report_generation_workflow(Arc::new(state_clone), command).await
{
error!("Error running report generation workflow: {:?}", e);
}
}
Err(e) => {
error!("Failed to deserialize GenerateReportCommand: {}", e);
}
}
});
}
Ok(())
}