1use std::net::SocketAddr;
18use std::sync::Arc;
19
20use api::v1::flow::DirtyWindowRequests;
21use api::v1::{RowDeleteRequests, RowInsertRequests};
22use cache::{PARTITION_INFO_CACHE_NAME, TABLE_FLOWNODE_SET_CACHE_NAME, TABLE_ROUTE_CACHE_NAME};
23use catalog::CatalogManagerRef;
24use common_base::Plugins;
25use common_datasource::object_store::LocalFileAccess;
26use common_error::ext::BoxedError;
27use common_meta::cache::{LayeredCacheRegistryRef, TableFlownodeSetCacheRef, TableRouteCacheRef};
28use common_meta::key::TableMetadataManagerRef;
29use common_meta::key::flow::FlowMetadataManagerRef;
30use common_meta::kv_backend::KvBackendRef;
31use common_meta::node_manager::{Flownode, NodeManagerRef};
32use common_meta::procedure_executor::ProcedureExecutorRef;
33use common_query::Output;
34use common_runtime::JoinHandle;
35use common_telemetry::tracing::info;
36use futures::TryStreamExt;
37use greptime_proto::v1::flow::{FlowRequest, FlowResponse, InsertRequests, flow_server};
38use itertools::Itertools;
39use operator::delete::Deleter;
40use operator::insert::Inserter;
41use operator::statement::StatementExecutor;
42use partition::cache::PartitionInfoCacheRef;
43use partition::manager::PartitionRuleManager;
44use query::{QueryEngine, QueryEngineFactory};
45use servers::add_service;
46use servers::grpc::builder::GrpcServerBuilder;
47use servers::grpc::{GrpcServer, GrpcServerConfig};
48use servers::http::HttpServerBuilder;
49use servers::metrics_handler::MetricsHandler;
50use servers::server::{ServerHandler, ServerHandlers};
51use session::context::QueryContextRef;
52use snafu::{OptionExt, ResultExt};
53use tokio::sync::{Mutex, broadcast, oneshot};
54use tonic::codec::CompressionEncoding;
55use tonic::{Request, Response, Status};
56
57use crate::adapter::flownode_impl::{FlowDualEngine, FlowDualEngineRef};
58use crate::adapter::{FlowStreamingEngineRef, create_worker};
59use crate::batching_mode::engine::BatchingEngine;
60use crate::error::{
61 CacheRequiredSnafu, DatafusionSnafu, ExternalSnafu, ListFlowsSnafu, ParseAddrSnafu,
62 ShutdownServerSnafu, StartServerSnafu, UnexpectedSnafu, to_status_with_last_err,
63};
64use crate::heartbeat::HeartbeatTask;
65use crate::metrics::{METRIC_FLOW_PROCESSING_TIME, METRIC_FLOW_ROWS};
66use crate::transform::register_function_to_query_engine;
67use crate::utils::{SizeReportSender, StateReportHandler};
68use crate::{Error, FlownodeOptions, FrontendClient, StreamingEngine};
69
70pub const FLOW_NODE_SERVER_NAME: &str = "FLOW_NODE_SERVER";
71#[derive(Clone)]
73pub struct FlowService {
74 pub dual_engine: FlowDualEngineRef,
75}
76
77impl FlowService {
78 pub fn new(manager: FlowDualEngineRef) -> Self {
79 Self {
80 dual_engine: manager,
81 }
82 }
83}
84
85#[async_trait::async_trait]
86impl flow_server::Flow for FlowService {
87 async fn handle_create_remove(
88 &self,
89 request: Request<FlowRequest>,
90 ) -> Result<Response<FlowResponse>, Status> {
91 let _timer = METRIC_FLOW_PROCESSING_TIME
92 .with_label_values(&["ddl"])
93 .start_timer();
94
95 let request = request.into_inner();
96 self.dual_engine
97 .handle(request)
98 .await
99 .map_err(|err| {
100 common_telemetry::error!(err; "Failed to handle flow request");
101 err
102 })
103 .map(Response::new)
104 .map_err(to_status_with_last_err)
105 }
106
107 async fn handle_mirror_request(
108 &self,
109 request: Request<InsertRequests>,
110 ) -> Result<Response<FlowResponse>, Status> {
111 let _timer = METRIC_FLOW_PROCESSING_TIME
112 .with_label_values(&["insert"])
113 .start_timer();
114
115 let request = request.into_inner();
116 let mut row_count = 0;
118 let request = api::v1::region::InsertRequests {
119 requests: request
120 .requests
121 .into_iter()
122 .map(|insert| {
123 insert.rows.as_ref().inspect(|x| row_count += x.rows.len());
124 api::v1::region::InsertRequest {
125 region_id: insert.region_id,
126 rows: insert.rows,
127 partition_expr_version: insert.partition_expr_version,
128 }
129 })
130 .collect_vec(),
131 };
132
133 METRIC_FLOW_ROWS
134 .with_label_values(&["in"])
135 .inc_by(row_count as u64);
136
137 self.dual_engine
138 .handle_inserts(request)
139 .await
140 .map(Response::new)
141 .map_err(to_status_with_last_err)
142 }
143
144 async fn handle_mark_dirty_time_window(
145 &self,
146 reqs: Request<DirtyWindowRequests>,
147 ) -> Result<Response<FlowResponse>, Status> {
148 self.dual_engine
149 .handle_mark_window_dirty(reqs.into_inner())
150 .await
151 .map(Response::new)
152 .map_err(to_status_with_last_err)
153 }
154}
155
156#[derive(Clone)]
157pub struct FlownodeServer {
158 inner: Arc<FlownodeServerInner>,
159}
160
161struct FlownodeServerInner {
165 worker_shutdown_tx: Mutex<broadcast::Sender<()>>,
167 server_shutdown_tx: Mutex<broadcast::Sender<()>>,
169 streaming_task_handler: Mutex<Option<JoinHandle<()>>>,
171 state_report_task_handler: Mutex<Option<JoinHandle<()>>>,
173 flow_service: FlowService,
174}
175
176impl FlownodeServer {
177 pub fn new(flow_service: FlowService) -> Self {
178 let (tx, _rx) = broadcast::channel::<()>(1);
179 let (server_tx, _server_rx) = broadcast::channel::<()>(1);
180 Self {
181 inner: Arc::new(FlownodeServerInner {
182 flow_service,
183 worker_shutdown_tx: Mutex::new(tx),
184 server_shutdown_tx: Mutex::new(server_tx),
185 streaming_task_handler: Mutex::new(None),
186 state_report_task_handler: Mutex::new(None),
187 }),
188 }
189 }
190
191 async fn start_workers(&self) -> Result<(), Error> {
195 let manager_ref = self.inner.flow_service.dual_engine.clone();
196 let mut state_report_task_handler = self.inner.state_report_task_handler.lock().await;
197 let started_state_report_task = state_report_task_handler.is_none();
198 if state_report_task_handler.is_none() {
199 *state_report_task_handler = manager_ref.clone().start_state_report_task().await;
200 }
201 drop(state_report_task_handler);
202 let handle = manager_ref
203 .streaming_engine()
204 .run_background(Some(self.inner.worker_shutdown_tx.lock().await.subscribe()));
205 self.inner
206 .streaming_task_handler
207 .lock()
208 .await
209 .replace(handle);
210
211 if let Err(err) = self
212 .inner
213 .flow_service
214 .dual_engine
215 .start_flow_consistent_check_task()
216 .await
217 {
218 self.rollback_started_workers(started_state_report_task)
219 .await;
220 return Err(err);
221 }
222
223 Ok(())
224 }
225
226 async fn rollback_started_workers(&self, abort_state_report_task: bool) {
227 let tx = self.inner.worker_shutdown_tx.lock().await;
228 if tx.send(()).is_err() {
229 info!("Receiver dropped, the flow node server has already shutdown");
230 }
231 drop(tx);
232
233 if let Some(handle) = self.inner.streaming_task_handler.lock().await.take() {
234 handle.abort();
235 }
236
237 if abort_state_report_task
238 && let Some(handle) = self.inner.state_report_task_handler.lock().await.take()
239 {
240 handle.abort();
241 }
242 }
243
244 async fn stop_workers(&self) -> Result<(), Error> {
246 let tx = self.inner.worker_shutdown_tx.lock().await;
247 if tx.send(()).is_err() {
248 info!("Receiver dropped, the flow node server has already shutdown");
249 }
250 self.inner
253 .flow_service
254 .dual_engine
255 .stop_flow_consistent_check_task()
256 .await?;
257 Ok(())
258 }
259}
260
261impl FlownodeServer {
262 pub fn create_flow_service(&self) -> flow_server::FlowServer<impl flow_server::Flow> {
263 flow_server::FlowServer::new(self.inner.flow_service.clone())
264 .accept_compressed(CompressionEncoding::Gzip)
265 .send_compressed(CompressionEncoding::Gzip)
266 .accept_compressed(CompressionEncoding::Zstd)
267 .send_compressed(CompressionEncoding::Zstd)
268 }
269}
270
271pub struct FlownodeInstance {
273 flownode_server: FlownodeServer,
274 services: ServerHandlers,
275 heartbeat_task: Option<HeartbeatTask>,
276}
277
278impl FlownodeInstance {
279 pub async fn start(&mut self) -> Result<(), crate::Error> {
280 if let Some(task) = &self.heartbeat_task {
281 task.start().await?;
282 }
283
284 self.flownode_server.start_workers().await?;
285
286 self.services.start_all().await.context(StartServerSnafu)?;
287
288 Ok(())
289 }
290 pub async fn shutdown(&mut self) -> Result<(), Error> {
291 self.services
292 .shutdown_all()
293 .await
294 .context(ShutdownServerSnafu)?;
295
296 self.flownode_server.stop_workers().await?;
297
298 if let Some(task) = &self.heartbeat_task {
299 task.shutdown();
300 }
301
302 Ok(())
303 }
304
305 pub fn flownode_server(&self) -> &FlownodeServer {
306 &self.flownode_server
307 }
308
309 pub fn flow_engine(&self) -> FlowDualEngineRef {
310 self.flownode_server.inner.flow_service.dual_engine.clone()
311 }
312
313 pub fn setup_services(&mut self, services: ServerHandlers) {
314 self.services = services;
315 }
316}
317
318pub struct FlownodeBuilder {
320 opts: FlownodeOptions,
321 plugins: Plugins,
322 table_meta: TableMetadataManagerRef,
323 catalog_manager: CatalogManagerRef,
324 flow_metadata_manager: FlowMetadataManagerRef,
325 heartbeat_task: Option<HeartbeatTask>,
326 state_report_handler: Option<StateReportHandler>,
328 frontend_client: Arc<FrontendClient>,
329}
330
331impl FlownodeBuilder {
332 pub fn new(
334 opts: FlownodeOptions,
335 plugins: Plugins,
336 table_meta: TableMetadataManagerRef,
337 catalog_manager: CatalogManagerRef,
338 flow_metadata_manager: FlowMetadataManagerRef,
339 frontend_client: Arc<FrontendClient>,
340 ) -> Self {
341 Self {
342 opts,
343 plugins,
344 table_meta,
345 catalog_manager,
346 flow_metadata_manager,
347 heartbeat_task: None,
348 state_report_handler: None,
349 frontend_client,
350 }
351 }
352
353 pub fn with_heartbeat_task(self, heartbeat_task: HeartbeatTask) -> Self {
354 let (sender, receiver) = SizeReportSender::new();
355 Self {
356 heartbeat_task: Some(heartbeat_task.with_query_stat_size(sender)),
357 state_report_handler: Some(receiver),
358 ..self
359 }
360 }
361
362 pub fn opts(&self) -> &FlownodeOptions {
363 &self.opts
364 }
365
366 pub fn table_meta(&self) -> &TableMetadataManagerRef {
367 &self.table_meta
368 }
369
370 pub fn catalog_manager(&self) -> &CatalogManagerRef {
371 &self.catalog_manager
372 }
373
374 pub fn flow_metadata_manager(&self) -> &FlowMetadataManagerRef {
375 &self.flow_metadata_manager
376 }
377
378 pub fn frontend_client(&self) -> &Arc<FrontendClient> {
379 &self.frontend_client
380 }
381
382 pub fn set_plugins(&mut self, plugins: Plugins) {
383 self.plugins = plugins;
384 }
385
386 pub async fn build(mut self) -> Result<FlownodeInstance, Error> {
387 let query_engine_factory = QueryEngineFactory::try_new_with_plugins(
389 self.catalog_manager.clone(),
391 None,
392 None,
393 None,
394 None,
395 None,
396 false,
397 Default::default(),
398 self.opts.query.clone(),
399 )
400 .context(DatafusionSnafu {
401 context: "Failed to build query engine",
402 })?;
403 let manager = Arc::new(
404 self.build_manager(query_engine_factory.query_engine())
405 .await?,
406 );
407 let batching = Arc::new(BatchingEngine::new(
408 self.frontend_client.clone(),
409 query_engine_factory.query_engine(),
410 self.flow_metadata_manager.clone(),
411 self.table_meta.clone(),
412 self.catalog_manager.clone(),
413 self.opts.flow.batching_mode.clone(),
414 ));
415 let dual = Arc::new(FlowDualEngine::new(
416 manager.clone(),
417 batching,
418 self.flow_metadata_manager.clone(),
419 self.catalog_manager.clone(),
420 self.plugins.clone(),
421 ));
422 if let Some(handler) = self.state_report_handler.take() {
423 dual.set_state_report_handler(handler).await;
424 }
425
426 let server = FlownodeServer::new(FlowService::new(dual));
427
428 let heartbeat_task = self.heartbeat_task;
429
430 let instance = FlownodeInstance {
431 flownode_server: server,
432 services: ServerHandlers::default(),
433 heartbeat_task,
434 };
435 Ok(instance)
436 }
437
438 async fn build_manager(
441 &mut self,
442 query_engine: Arc<dyn QueryEngine>,
443 ) -> Result<StreamingEngine, Error> {
444 let table_meta = self.table_meta.clone();
445
446 register_function_to_query_engine(&query_engine);
447
448 let num_workers = self.opts.flow.num_workers;
449
450 let node_id = self.opts.node_id.map(|id| id as u32);
451
452 let mut man = StreamingEngine::new(node_id, query_engine, table_meta);
453 for worker_id in 0..num_workers {
454 let (tx, rx) = oneshot::channel();
455
456 let _handle = std::thread::Builder::new()
457 .name(format!("flow-worker-{}", worker_id))
458 .spawn(move || {
459 let (handle, mut worker) = create_worker();
460 let _ = tx.send(handle);
461 info!("Flow Worker started in new thread");
462 worker.run();
463 });
464 let worker_handle = rx.await.map_err(|e| {
465 UnexpectedSnafu {
466 reason: format!("Failed to receive worker handle: {}", e),
467 }
468 .build()
469 })?;
470 man.add_worker_handle(worker_handle);
471 }
472 info!("Flow Node Manager started");
473 Ok(man)
474 }
475}
476
477pub struct FlownodeServiceBuilder<'a> {
479 opts: &'a FlownodeOptions,
480 grpc_server: Option<GrpcServer>,
481 enable_http_service: bool,
482}
483
484impl<'a> FlownodeServiceBuilder<'a> {
485 pub fn new(opts: &'a FlownodeOptions) -> Self {
486 Self {
487 opts,
488 grpc_server: None,
489 enable_http_service: false,
490 }
491 }
492
493 pub fn enable_http_service(self) -> Self {
494 Self {
495 enable_http_service: true,
496 ..self
497 }
498 }
499
500 pub fn with_grpc_server(self, grpc_server: GrpcServer) -> Self {
501 Self {
502 grpc_server: Some(grpc_server),
503 ..self
504 }
505 }
506
507 pub fn with_default_grpc_server(mut self, flownode_server: &FlownodeServer) -> Self {
508 let grpc_server = Self::grpc_server_builder(self.opts, flownode_server).build();
509 self.grpc_server = Some(grpc_server);
510 self
511 }
512
513 pub fn build(mut self) -> Result<ServerHandlers, Error> {
514 let handlers = ServerHandlers::default();
515 if let Some(grpc_server) = self.grpc_server.take() {
516 let addr: SocketAddr = self.opts.grpc.bind_addr.parse().context(ParseAddrSnafu {
517 addr: &self.opts.grpc.bind_addr,
518 })?;
519 let handler: ServerHandler = (Box::new(grpc_server), addr);
520 handlers.insert(handler);
521 }
522
523 if self.enable_http_service {
524 let http_server = HttpServerBuilder::new(self.opts.http.clone())
525 .with_metrics_handler(MetricsHandler)
526 .build();
527 let addr: SocketAddr = self.opts.http.addr.parse().context(ParseAddrSnafu {
528 addr: &self.opts.http.addr,
529 })?;
530 let handler: ServerHandler = (Box::new(http_server), addr);
531 handlers.insert(handler);
532 }
533 Ok(handlers)
534 }
535
536 pub fn grpc_server_builder(
537 opts: &FlownodeOptions,
538 flownode_server: &FlownodeServer,
539 ) -> GrpcServerBuilder {
540 let config = GrpcServerConfig {
541 max_recv_message_size: opts.grpc.max_recv_message_size.as_bytes() as usize,
542 max_send_message_size: opts.grpc.max_send_message_size.as_bytes() as usize,
543 tls: opts.grpc.tls.clone(),
544 max_connection_age: opts.grpc.max_connection_age,
545 };
546 let service = flownode_server.create_flow_service();
547 let runtime = common_runtime::global_runtime();
548 let mut builder = GrpcServerBuilder::new(config, runtime);
549 add_service!(builder, service);
550 builder
551 }
552}
553
554#[derive(Clone)]
559pub struct FrontendInvoker {
560 inserter: Arc<Inserter>,
561 deleter: Arc<Deleter>,
562 statement_executor: Arc<StatementExecutor>,
563}
564
565impl FrontendInvoker {
566 pub fn new(
567 inserter: Arc<Inserter>,
568 deleter: Arc<Deleter>,
569 statement_executor: Arc<StatementExecutor>,
570 ) -> Self {
571 Self {
572 inserter,
573 deleter,
574 statement_executor,
575 }
576 }
577
578 pub async fn build_from(
579 flow_streaming_engine: FlowStreamingEngineRef,
580 catalog_manager: CatalogManagerRef,
581 kv_backend: KvBackendRef,
582 layered_cache_registry: LayeredCacheRegistryRef,
583 procedure_executor: ProcedureExecutorRef,
584 node_manager: NodeManagerRef,
585 origin_frontend_addr: String,
586 ) -> Result<FrontendInvoker, Error> {
587 let table_route_cache: TableRouteCacheRef =
588 layered_cache_registry.get().context(CacheRequiredSnafu {
589 name: TABLE_ROUTE_CACHE_NAME,
590 })?;
591 let partition_info_cache: PartitionInfoCacheRef =
592 layered_cache_registry.get().context(CacheRequiredSnafu {
593 name: PARTITION_INFO_CACHE_NAME,
594 })?;
595
596 let partition_manager = Arc::new(PartitionRuleManager::new(
597 kv_backend.clone(),
598 table_route_cache.clone(),
599 partition_info_cache.clone(),
600 ));
601
602 let table_flownode_cache: TableFlownodeSetCacheRef =
603 layered_cache_registry.get().context(CacheRequiredSnafu {
604 name: TABLE_FLOWNODE_SET_CACHE_NAME,
605 })?;
606
607 let inserter = Arc::new(Inserter::new(
611 catalog_manager.clone(),
612 partition_manager.clone(),
613 node_manager.clone(),
614 table_flownode_cache,
615 true,
616 ));
617
618 let deleter = Arc::new(Deleter::new(
619 catalog_manager.clone(),
620 partition_manager.clone(),
621 node_manager.clone(),
622 ));
623
624 let query_engine = flow_streaming_engine.query_engine.clone();
625
626 let statement_executor = Arc::new(StatementExecutor::new(
627 catalog_manager.clone(),
628 query_engine.clone(),
629 procedure_executor.clone(),
630 kv_backend.clone(),
631 layered_cache_registry.clone(),
632 inserter.clone(),
633 partition_manager,
634 None,
635 origin_frontend_addr,
636 LocalFileAccess::Disabled,
637 ));
638
639 let invoker = FrontendInvoker::new(inserter, deleter, statement_executor);
640 Ok(invoker)
641 }
642}
643
644impl FrontendInvoker {
645 pub async fn row_inserts(
646 &self,
647 requests: RowInsertRequests,
648 ctx: QueryContextRef,
649 ) -> common_frontend::error::Result<Output> {
650 let _timer = METRIC_FLOW_PROCESSING_TIME
651 .with_label_values(&["output_insert"])
652 .start_timer();
653
654 self.inserter
655 .handle_row_inserts(requests, ctx, &self.statement_executor, false, false)
656 .await
657 .map_err(BoxedError::new)
658 .context(common_frontend::error::ExternalSnafu)
659 }
660
661 pub async fn row_deletes(
662 &self,
663 requests: RowDeleteRequests,
664 ctx: QueryContextRef,
665 ) -> common_frontend::error::Result<Output> {
666 let _timer = METRIC_FLOW_PROCESSING_TIME
667 .with_label_values(&["output_delete"])
668 .start_timer();
669
670 self.deleter
671 .handle_row_deletes(requests, ctx)
672 .await
673 .map_err(BoxedError::new)
674 .context(common_frontend::error::ExternalSnafu)
675 }
676
677 pub fn statement_executor(&self) -> Arc<StatementExecutor> {
678 self.statement_executor.clone()
679 }
680}
681
682pub(crate) async fn get_all_flow_ids(
684 flow_metadata_manager: &FlowMetadataManagerRef,
685 catalog_manager: &CatalogManagerRef,
686 nodeid: Option<u64>,
687) -> Result<Vec<u32>, Error> {
688 let ret = if let Some(nodeid) = nodeid {
689 let flow_ids_one_node = flow_metadata_manager
690 .flownode_flow_manager()
691 .flows(nodeid)
692 .try_collect::<Vec<_>>()
693 .await
694 .context(ListFlowsSnafu { id: Some(nodeid) })?;
695 flow_ids_one_node.into_iter().map(|(id, _)| id).collect()
696 } else {
697 let all_catalogs = catalog_manager
698 .catalog_names()
699 .await
700 .map_err(BoxedError::new)
701 .context(ExternalSnafu)?;
702 let mut all_flow_ids = vec![];
703 for catalog in all_catalogs {
704 let flows = flow_metadata_manager
705 .flow_name_manager()
706 .flow_names(&catalog)
707 .await
708 .try_collect::<Vec<_>>()
709 .await
710 .map_err(BoxedError::new)
711 .context(ExternalSnafu)?;
712
713 all_flow_ids.extend(flows.into_iter().map(|(_, id)| id.flow_id()));
714 }
715 all_flow_ids
716 };
717
718 Ok(ret)
719}
720
721#[cfg(test)]
722mod tests {
723 use std::sync::Arc;
724 use std::time::Duration;
725
726 use api::v1::HealthCheckRequest;
727 use api::v1::health_check_client::HealthCheckClient;
728 use api::v1::meta::Role;
729 use catalog::memory::new_memory_catalog_manager;
730 use common_base::Plugins;
731 use common_meta::key::TableMetadataManager;
732 use common_meta::key::flow::FlowMetadataManager;
733 use common_meta::kv_backend::memory::MemoryKvBackend;
734 use meta_client::client::MetaClient;
735 use query::options::QueryOptions;
736 use servers::grpc::GRPC_SERVER;
737
738 use super::*;
739 use crate::adapter::flownode_impl::FlowDualEngine;
740 use crate::batching_mode::BatchingModeOptions;
741 use crate::batching_mode::engine::BatchingEngine;
742 use crate::utils::SizeReportSender;
743
744 async fn new_test_flownode_server() -> (FlownodeServer, SizeReportSender) {
745 let (frontend_client, _handler) =
746 FrontendClient::from_empty_grpc_handler(QueryOptions::default());
747
748 new_test_flownode_server_with_frontend_client(
749 frontend_client,
750 BatchingModeOptions::default(),
751 None,
752 )
753 .await
754 }
755
756 async fn new_test_flownode_server_with_frontend_client(
757 frontend_client: FrontendClient,
758 batching_opts: BatchingModeOptions,
759 node_id: Option<u32>,
760 ) -> (FlownodeServer, SizeReportSender) {
761 let kv_backend = Arc::new(MemoryKvBackend::new());
762 let table_meta = Arc::new(TableMetadataManager::new(kv_backend.clone()));
763 table_meta.init().await.unwrap();
764 let flow_meta = Arc::new(FlowMetadataManager::new(kv_backend.clone()));
765 let catalog_manager = new_memory_catalog_manager().unwrap();
766 let query_engine = crate::test_utils::create_test_query_engine();
767
768 let streaming_engine = Arc::new(StreamingEngine::new(
769 node_id,
770 query_engine.clone(),
771 table_meta.clone(),
772 ));
773 let batching_engine = Arc::new(BatchingEngine::new(
774 Arc::new(frontend_client),
775 query_engine,
776 flow_meta.clone(),
777 table_meta,
778 catalog_manager.clone(),
779 batching_opts,
780 ));
781 let dual_engine = Arc::new(FlowDualEngine::new(
782 streaming_engine,
783 batching_engine,
784 flow_meta,
785 catalog_manager,
786 Plugins::new(),
787 ));
788
789 let (report_sender, report_handler) = SizeReportSender::new();
790 dual_engine.set_state_report_handler(report_handler).await;
791
792 let server = FlownodeServer::new(FlowService::new(dual_engine));
793 (server, report_sender)
794 }
795
796 #[tokio::test]
797 async fn test_state_report_handler_survives_worker_restart() {
798 let (server, report_sender) = new_test_flownode_server().await;
799
800 server.start_workers().await.unwrap();
801 report_sender.query(Duration::from_secs(3)).await.unwrap();
802
803 server.stop_workers().await.unwrap();
804 report_sender.query(Duration::from_secs(3)).await.unwrap();
805
806 server.start_workers().await.unwrap();
807 report_sender.query(Duration::from_secs(3)).await.unwrap();
808
809 server.stop_workers().await.unwrap();
810 }
811
812 #[tokio::test]
813 async fn test_start_workers_rolls_back_on_check_task_start_failure() {
814 let batching_opts = BatchingModeOptions {
815 experimental_frontend_scan_timeout: Duration::from_millis(1),
816 ..Default::default()
817 };
818 let frontend_client = FrontendClient::from_meta_client(
819 Arc::new(MetaClient::new(0, Role::Frontend)),
820 QueryOptions::default(),
821 batching_opts.clone(),
822 )
823 .unwrap();
824 let (server, _report_sender) =
825 new_test_flownode_server_with_frontend_client(frontend_client, batching_opts, Some(1))
826 .await;
827
828 server.start_workers().await.unwrap_err();
829
830 assert!(server.inner.streaming_task_handler.lock().await.is_none());
831 assert!(
832 server
833 .inner
834 .state_report_task_handler
835 .lock()
836 .await
837 .is_none()
838 );
839 }
840
841 #[tokio::test]
842 async fn test_service_builder_registers_reachable_health_check() {
843 let (flownode_server, _report_sender) = new_test_flownode_server().await;
845 let mut opts = FlownodeOptions::default();
846 opts.grpc.bind_addr = "127.0.0.1:0".to_string();
847 let mut services = FlownodeServiceBuilder::new(&opts)
848 .with_default_grpc_server(&flownode_server)
849 .build()
850 .unwrap();
851 services.start_all().await.unwrap();
852 let addr = services.addr(GRPC_SERVER).unwrap();
853
854 let mut client = HealthCheckClient::connect(format!("http://{addr}"))
856 .await
857 .unwrap();
858 let result = client.health_check(HealthCheckRequest {}).await;
859
860 services.shutdown_all().await.unwrap();
861
862 assert!(result.is_ok());
864 }
865}