11use crate :: data_model:: StreamingConfig ;
22use crate :: precompute_engine:: config:: PrecomputeEngineConfig ;
3- use crate :: precompute_engine:: ingest_handler:: {
4- handle_prometheus_ingest, handle_victoriametrics_ingest, IngestState ,
5- } ;
3+ use crate :: precompute_engine:: ingest_source:: { IngestContext , IngestSource } ;
64use crate :: precompute_engine:: output_sink:: OutputSink ;
75use crate :: precompute_engine:: series_router:: { SeriesRouter , WorkerMessage } ;
86use crate :: precompute_engine:: worker:: { Worker , WorkerRuntimeConfig } ;
97use arc_swap:: ArcSwap ;
108use asap_types:: aggregation_config:: AggregationConfig ;
11- use axum:: { routing:: post, Router } ;
129use std:: collections:: HashMap ;
1310use std:: sync:: atomic:: { AtomicI64 , AtomicUsize } ;
1411use std:: sync:: Arc ;
15- use tokio:: net:: TcpListener ;
1612use tokio:: sync:: mpsc;
1713use tracing:: { info, warn} ;
1814
@@ -64,14 +60,15 @@ impl PrecomputeEngineHandle {
6460
6561/// The top-level precompute engine orchestrator.
6662///
67- /// Creates worker threads, the series router, and the Axum ingest server .
63+ /// Creates worker threads and drives all registered ingest sources .
6864/// Call `handle()` before `run()` to obtain a `PrecomputeEngineHandle` for
6965/// applying runtime config updates while the engine is running.
7066pub struct PrecomputeEngine {
7167 config : PrecomputeEngineConfig ,
7268 streaming_config : Arc < StreamingConfig > ,
7369 output_sink : Arc < dyn OutputSink > ,
7470 diagnostics : Arc < PrecomputeWorkerDiagnostics > ,
71+ sources : Vec < Box < dyn IngestSource > > ,
7572 /// Channels created at construction so handle() can be extracted before run().
7673 senders : Vec < mpsc:: Sender < WorkerMessage > > ,
7774 receivers : Option < Vec < mpsc:: Receiver < WorkerMessage > > > ,
@@ -84,6 +81,7 @@ impl PrecomputeEngine {
8481 config : PrecomputeEngineConfig ,
8582 streaming_config : Arc < StreamingConfig > ,
8683 output_sink : Arc < dyn OutputSink > ,
84+ sources : Vec < Box < dyn IngestSource > > ,
8785 ) -> Self {
8886 let worker_group_counts = ( 0 ..config. num_workers )
8987 . map ( |_| Arc :: new ( AtomicUsize :: new ( 0 ) ) )
@@ -96,8 +94,6 @@ impl PrecomputeEngine {
9694 worker_watermarks,
9795 } ) ;
9896
99- // Build channels and initial agg_configs at construction time so that
100- // handle() can be called before run().
10197 let channel_size = config. channel_buffer_size ;
10298 let mut senders = Vec :: with_capacity ( config. num_workers ) ;
10399 let mut receivers = Vec :: with_capacity ( config. num_workers ) ;
@@ -119,6 +115,7 @@ impl PrecomputeEngine {
119115 streaming_config,
120116 output_sink,
121117 diagnostics,
118+ sources,
122119 senders,
123120 receivers : Some ( receivers) ,
124121 ingest_agg_configs,
@@ -139,8 +136,8 @@ impl PrecomputeEngine {
139136 }
140137 }
141138
142- /// Start the precompute engine. This spawns worker tasks and the HTTP
143- /// ingest server , then blocks until shutdown.
139+ /// Start the precompute engine. This spawns worker tasks and all registered
140+ /// ingest sources , then blocks until shutdown.
144141 pub async fn run ( mut self ) -> Result < ( ) , Box < dyn std:: error:: Error + Send + Sync > > {
145142 let num_workers = self . config . num_workers ;
146143
@@ -185,48 +182,49 @@ impl PrecomputeEngine {
185182 worker_handles. push ( handle) ;
186183 }
187184
188- info ! (
189- "PrecomputeEngine started with {} workers on port {}" ,
190- num_workers, self . config. ingest_port
191- ) ;
185+ info ! ( "PrecomputeEngine started with {} workers" , num_workers) ;
192186
193- // Build the ingest state, sharing the same Arc<ArcSwap> as the handle so
194- // that PrecomputeEngineHandle::update_streaming_config swaps are visible here.
195- let ingest_state = Arc :: new ( IngestState {
196- router ,
197- samples_ingested : std :: sync :: atomic :: AtomicU64 :: new ( 0 ) ,
187+ // Build the ingest context shared by all sources.
188+ // The ArcSwap pointer is the same one held by PrecomputeEngineHandle, so
189+ // handle.update_streaming_config() is immediately visible to every source.
190+ let ctx = IngestContext {
191+ router : router . clone ( ) ,
198192 agg_configs : self . ingest_agg_configs . clone ( ) ,
199193 pass_raw_samples : self . config . pass_raw_samples ,
200- } ) ;
194+ } ;
201195
202- // Start flush timer
203- let flush_state = ingest_state . clone ( ) ;
196+ // Flush timer: periodically signal workers to close idle windows.
197+ let flush_router = router . clone ( ) ;
204198 let flush_interval_ms = self . config . flush_interval_ms ;
205199 tokio:: spawn ( async move {
206200 let mut interval =
207201 tokio:: time:: interval ( tokio:: time:: Duration :: from_millis ( flush_interval_ms) ) ;
208202 loop {
209203 interval. tick ( ) . await ;
210- if let Err ( e) = flush_state . router . broadcast_flush ( ) . await {
204+ if let Err ( e) = flush_router . broadcast_flush ( ) . await {
211205 warn ! ( "Flush broadcast error: {}" , e) ;
212206 break ;
213207 }
214208 }
215209 } ) ;
216210
217- // Start the Axum HTTP server for ingest (Prometheus + VictoriaMetrics)
218- let app = Router :: new ( )
219- . route ( "/api/v1/write" , post ( handle_prometheus_ingest) )
220- . route ( "/api/v1/import" , post ( handle_victoriametrics_ingest) )
221- . with_state ( ingest_state) ;
222-
223- let addr = format ! ( "0.0.0.0:{}" , self . config. ingest_port) ;
224- info ! ( "Ingest server listening on {}" , addr) ;
211+ // Spawn each ingest source.
212+ let mut source_handles = Vec :: with_capacity ( self . sources . len ( ) ) ;
213+ for source in self . sources {
214+ let ctx = ctx. clone ( ) ;
215+ let handle = tokio:: spawn ( async move {
216+ if let Err ( e) = source. run ( ctx) . await {
217+ warn ! ( "Ingest source error: {}" , e) ;
218+ }
219+ } ) ;
220+ source_handles. push ( handle) ;
221+ }
225222
226- let listener = TcpListener :: bind ( & addr) . await ?;
227- axum:: serve ( listener, app) . await ?;
223+ // Block until all sources finish (normally only on shutdown).
224+ for handle in source_handles {
225+ let _ = handle. await ;
226+ }
228227
229- // Wait for workers to finish (this only happens on shutdown)
230228 for handle in worker_handles {
231229 let _ = handle. await ;
232230 }
0 commit comments