1use std::fmt::{Debug, Formatter};
16use std::panic::AssertUnwindSafe;
17use std::sync::Arc;
18
19use anyhow::Context;
20use futures::StreamExt;
21use parking_lot::Mutex;
22use risingwave_common::array::DataChunk;
23use risingwave_common::util::panic::FutureCatchUnwindExt;
24use risingwave_common::util::runtime::BackgroundShutdownRuntime;
25use risingwave_common::util::tracing::TracingContext;
26use risingwave_expr::expr_context::expr_context_scope;
27use risingwave_pb::PbFieldNotFound;
28use risingwave_pb::batch_plan::{PbTaskId, PbTaskOutputId, PlanFragment};
29use risingwave_pb::plan_common::ExprContext;
30use risingwave_pb::task_service::task_info_response::TaskStatus;
31use risingwave_pb::task_service::{GetDataResponse, TaskInfoResponse};
32use thiserror_ext::AsReport;
33use tokio::select;
34use tokio::task::JoinHandle;
35use tracing::Instrument;
36
37use crate::error::BatchError::SenderError;
38use crate::error::{BatchError, Result, SharedResult};
39use crate::executor::{BoxedExecutor, ExecutorBuilder};
40use crate::rpc::service::exchange::ExchangeWriter;
41use crate::rpc::service::task_service::TaskInfoResponseResult;
42use crate::task::BatchTaskContext;
43use crate::task::channel::{ChanReceiverImpl, ChanSenderImpl, create_output_channel};
44
45pub const TASK_STATUS_BUFFER_SIZE: usize = 2;
47
48#[derive(Clone)]
56pub enum StateReporter {
57 Distributed(tokio::sync::mpsc::Sender<TaskInfoResponseResult>),
58 Mock(),
59}
60
61impl StateReporter {
62 pub async fn send(&mut self, val: TaskInfoResponse) -> Result<()> {
63 match self {
64 Self::Distributed(s) => s.send(Ok(val)).await.map_err(|_| SenderError),
65 Self::Mock() => Ok(()),
66 }
67 }
68
69 pub fn new_with_dist_sender(s: tokio::sync::mpsc::Sender<TaskInfoResponseResult>) -> Self {
70 Self::Distributed(s)
71 }
72
73 pub fn new_with_test() -> Self {
74 Self::Mock()
75 }
76}
77
78#[derive(PartialEq, Eq, Hash, Clone, Debug, Default)]
79pub struct TaskId {
80 pub task_id: u64,
81 pub stage_id: u32,
82 pub query_id: String,
83}
84
85#[derive(PartialEq, Eq, Hash, Clone, Default)]
86pub struct TaskOutputId {
87 pub task_id: TaskId,
88 pub output_id: u64,
89}
90
91impl Debug for TaskOutputId {
93 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
94 f.write_fmt(format_args!(
95 "TaskOutputId {{ query_id: \"{}\", stage_id: {}, task_id: {}, output_id: {} }}",
96 self.task_id.query_id, self.task_id.stage_id, self.task_id.task_id, self.output_id
97 ))
98 }
99}
100
101impl From<&PbTaskId> for TaskId {
102 fn from(prost: &PbTaskId) -> Self {
103 TaskId {
104 task_id: prost.task_id,
105 stage_id: prost.stage_id,
106 query_id: prost.query_id.clone(),
107 }
108 }
109}
110
111impl TaskId {
112 pub fn to_prost(&self) -> PbTaskId {
113 PbTaskId {
114 task_id: self.task_id,
115 stage_id: self.stage_id,
116 query_id: self.query_id.clone(),
117 }
118 }
119}
120
121impl TryFrom<&PbTaskOutputId> for TaskOutputId {
122 type Error = PbFieldNotFound;
123
124 fn try_from(prost: &PbTaskOutputId) -> std::result::Result<Self, PbFieldNotFound> {
125 Ok(TaskOutputId {
126 task_id: TaskId::from(prost.get_task_id()?),
127 output_id: prost.get_output_id(),
128 })
129 }
130}
131
132impl TaskOutputId {
133 pub fn to_prost(&self) -> PbTaskOutputId {
134 PbTaskOutputId {
135 task_id: Some(self.task_id.to_prost()),
136 output_id: self.output_id,
137 }
138 }
139}
140
141pub struct TaskOutput {
142 receiver: ChanReceiverImpl,
143 output_id: TaskOutputId,
144 failure: Arc<Mutex<Option<Arc<BatchError>>>>,
145}
146
147impl std::fmt::Debug for TaskOutput {
148 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
149 f.debug_struct("TaskOutput")
150 .field("output_id", &self.output_id)
151 .field("failure", &self.failure)
152 .finish_non_exhaustive()
153 }
154}
155
156impl TaskOutput {
157 async fn take_data_inner(
160 &mut self,
161 writer: &mut impl ExchangeWriter,
162 at_most_num: Option<usize>,
163 ) -> Result<bool> {
164 let mut cnt: usize = 0;
165 let limited = at_most_num.is_some();
166 let at_most_num = at_most_num.unwrap_or(usize::MAX);
167 loop {
168 if limited && cnt >= at_most_num {
169 return Ok(false);
170 }
171 match self.receiver.recv().await {
172 Ok(Some(chunk)) => {
174 trace!(
175 "Task output id: {:?}, data len: {:?}",
176 self.output_id,
177 chunk.cardinality()
178 );
179 let pb = chunk.to_protobuf().await;
180 let resp = GetDataResponse {
181 record_batch: Some(pb),
182 };
183 writer.write(Ok(resp)).await?;
184 }
185 Ok(None) => {
187 break;
188 }
189 Err(e) => {
191 writer.write(Err(tonic::Status::from(&*e))).await?;
192 break;
193 }
194 }
195 cnt += 1;
196 }
197 Ok(true)
198 }
199
200 pub async fn take_data_with_num(
203 &mut self,
204 writer: &mut impl ExchangeWriter,
205 num: usize,
206 ) -> Result<bool> {
207 self.take_data_inner(writer, Some(num)).await
208 }
209
210 pub async fn take_data(&mut self, writer: &mut impl ExchangeWriter) -> Result<()> {
212 let finish = self.take_data_inner(writer, None).await?;
213 assert!(finish);
214 Ok(())
215 }
216
217 pub async fn direct_take_data(&mut self) -> SharedResult<Option<DataChunk>> {
219 Ok(self.receiver.recv().await?.map(|c| c.into_data_chunk()))
220 }
221
222 pub fn id(&self) -> &TaskOutputId {
223 &self.output_id
224 }
225}
226
227#[derive(Clone, Debug)]
228pub enum ShutdownMsg {
229 Init,
231 Abort(String),
232 Cancel,
233}
234
235#[derive(Clone)]
237pub struct ShutdownSender(tokio::sync::watch::Sender<ShutdownMsg>);
238
239impl ShutdownSender {
240 pub fn cancel(&self) -> bool {
242 self.0.send(ShutdownMsg::Cancel).is_ok()
243 }
244
245 pub fn abort(&self, msg: impl Into<String>) -> bool {
247 self.0.send(ShutdownMsg::Abort(msg.into())).is_ok()
248 }
249}
250
251#[derive(Clone)]
253pub struct ShutdownToken(tokio::sync::watch::Receiver<ShutdownMsg>);
254
255impl ShutdownToken {
256 pub fn empty() -> Self {
258 Self::new().1
259 }
260
261 pub fn new() -> (ShutdownSender, Self) {
263 let (tx, rx) = tokio::sync::watch::channel(ShutdownMsg::Init);
264 (ShutdownSender(tx), ShutdownToken(rx))
265 }
266
267 pub fn check(&self) -> Result<()> {
269 match &*self.0.borrow() {
270 ShutdownMsg::Init => Ok(()),
271 msg => bail!("Receive shutdown msg: {msg:?}"),
272 }
273 }
274
275 pub async fn cancelled(&mut self) {
280 if matches!(*self.0.borrow(), ShutdownMsg::Init)
281 && let Err(_err) = self.0.changed().await
282 {
283 std::future::pending::<()>().await;
284 }
285 }
286
287 pub fn is_cancelled(&self) -> bool {
289 !matches!(*self.0.borrow(), ShutdownMsg::Init)
290 }
291
292 pub fn message(&self) -> ShutdownMsg {
294 self.0.borrow().clone()
295 }
296}
297
298pub struct BatchTaskExecution {
300 task_id: TaskId,
302
303 plan: PlanFragment,
305
306 state: Mutex<TaskStatus>,
308
309 receivers: Mutex<Vec<Option<ChanReceiverImpl>>>,
311
312 sender: ChanSenderImpl,
314
315 context: Arc<dyn BatchTaskContext>,
317
318 failure: Arc<Mutex<Option<Arc<BatchError>>>>,
320
321 runtime: Arc<BackgroundShutdownRuntime>,
323
324 shutdown_tx: ShutdownSender,
325 shutdown_rx: ShutdownToken,
326 heartbeat_join_handle: Mutex<Option<JoinHandle<()>>>,
327
328 await_tree_reg: Option<await_tree::Registry>,
331}
332
333impl BatchTaskExecution {
334 pub fn new(
335 prost_tid: &PbTaskId,
336 plan: PlanFragment,
337 context: Arc<dyn BatchTaskContext>,
338 runtime: Arc<BackgroundShutdownRuntime>,
339 await_tree_reg: Option<await_tree::Registry>,
340 ) -> Result<Self> {
341 let task_id = TaskId::from(prost_tid);
342
343 let (sender, receivers) = create_output_channel(
344 plan.get_exchange_info()?,
345 context.get_config().developer.output_channel_size,
346 )?;
347
348 let mut rts = Vec::new();
349 rts.extend(receivers.into_iter().map(Some));
350
351 let (shutdown_tx, shutdown_rx) = ShutdownToken::new();
352 Ok(Self {
353 task_id,
354 plan,
355 state: Mutex::new(TaskStatus::Pending),
356 receivers: Mutex::new(rts),
357 failure: Arc::new(Mutex::new(None)),
358 context,
359 runtime,
360 sender,
361 shutdown_tx,
362 shutdown_rx,
363 heartbeat_join_handle: Mutex::new(None),
364 await_tree_reg,
365 })
366 }
367
368 pub fn get_task_id(&self) -> &TaskId {
369 &self.task_id
370 }
371
372 pub async fn async_execute(
379 self: Arc<Self>,
380 state_tx: Option<StateReporter>,
381 tracing_context: TracingContext,
382 expr_context: ExprContext,
383 ) -> Result<()> {
384 let mut state_tx = state_tx;
385 trace!(
386 "Prepare executing plan [{:?}]: {}",
387 self.task_id,
388 serde_json::to_string_pretty(self.plan.get_root()?).unwrap()
389 );
390
391 let exec = expr_context_scope(
392 expr_context.clone(),
393 ExecutorBuilder::new(
394 self.plan.root.as_ref().unwrap(),
395 &self.task_id,
396 self.context.clone(),
397 self.shutdown_rx.clone(),
398 )
399 .build(),
400 )
401 .await?;
402
403 let sender = self.sender.clone();
404 let _failure = self.failure.clone();
405 let task_id = self.task_id.clone();
406
407 self.change_state_notify(TaskStatus::Running, state_tx.as_mut(), None)
411 .await?;
412
413 let t_1 = self.clone();
415 let this = self.clone();
416 async fn notify_panic(
417 this: &BatchTaskExecution,
418 state_tx: Option<&mut StateReporter>,
419 message: Option<&str>,
420 ) {
421 let err_str = if let Some(message) = message {
422 format!("execution panic: {}", message)
423 } else {
424 "execution panic".into()
425 };
426
427 if let Err(e) = this
428 .change_state_notify(TaskStatus::Failed, state_tx, Some(err_str))
429 .await
430 {
431 warn!(
432 error = %e.as_report(),
433 "The status receiver in FE has closed so the status push is failed",
434 );
435 }
436 }
437 let fut = async move {
439 trace!("Executing plan [{:?}]", task_id);
440 let sender = sender;
441 let mut state_tx_1 = state_tx.clone();
442
443 let task = |task_id: TaskId| async move {
444 let span = tracing_context.attach(tracing::info_span!(
445 "batch_execute",
446 task_id = task_id.task_id,
447 stage_id = task_id.stage_id,
448 query_id = task_id.query_id,
449 ));
450
451 expr_context_scope(
454 expr_context,
455 t_1.run(exec, sender, state_tx_1.as_mut()).instrument(span),
456 )
457 .await;
458 };
459
460 if let Err(error) = AssertUnwindSafe(task(task_id.clone()))
461 .rw_catch_unwind()
462 .await
463 {
464 let message = panic_message::get_panic_message(&error);
465 error!(?task_id, error = message, "Batch task panic");
466 notify_panic(&this, state_tx.as_mut(), message).await;
467 }
468 };
469
470 if let Some(reg) = self.await_tree_reg.clone() {
471 let key = crate::task::await_tree_key::BatchTask(self.task_id.clone());
472 let span = await_tree::span!(
473 "Batch Task (query {} stage {} task {})",
474 self.task_id.query_id,
475 self.task_id.stage_id,
476 self.task_id.task_id
477 );
478 self.runtime.spawn(reg.register(key, span).instrument(fut));
479 } else {
480 self.runtime.spawn(fut);
481 }
482
483 Ok(())
484 }
485
486 pub async fn change_state_notify(
488 &self,
489 task_status: TaskStatus,
490 state_tx: Option<&mut StateReporter>,
491 err_str: Option<String>,
492 ) -> Result<()> {
493 self.change_state(task_status);
494 if let Some(reporter) = state_tx {
496 reporter
497 .send(TaskInfoResponse {
498 task_id: Some(self.task_id.to_prost()),
499 task_status: task_status.into(),
500 error_message: err_str.unwrap_or("".to_owned()),
501 })
502 .await
503 } else {
504 Ok(())
505 }
506 }
507
508 pub fn change_state(&self, task_status: TaskStatus) {
509 *self.state.lock() = task_status;
510 tracing::debug!(
511 "Task {:?} state changed to {:?}",
512 &self.task_id,
513 task_status
514 );
515 }
516
517 async fn run(
518 &self,
519 root: BoxedExecutor,
520 mut sender: ChanSenderImpl,
521 state_tx: Option<&mut StateReporter>,
522 ) {
523 self.context
524 .batch_metrics()
525 .as_ref()
526 .inspect(|m| m.batch_manager_metrics().task_num.inc());
527 let mut data_chunk_stream = root.execute();
528 let mut state;
529 let mut error = None;
530
531 let mut shutdown_rx = self.shutdown_rx.clone();
532 loop {
533 select! {
534 biased;
535 _ = shutdown_rx.cancelled() => {
537 match self.shutdown_rx.message() {
538 ShutdownMsg::Abort(e) => {
539 error = Some(BatchError::Aborted(e));
540 state = TaskStatus::Aborted;
541 break;
542 }
543 ShutdownMsg::Cancel => {
544 state = TaskStatus::Cancelled;
545 break;
546 }
547 ShutdownMsg::Init => {
548 unreachable!("Init message should not be received here!")
549 }
550 }
551 }
552 data_chunk = data_chunk_stream.next()=> {
553 match data_chunk {
554 Some(Ok(data_chunk)) => {
555 if let Err(e) = sender.send(data_chunk).await {
556 match e {
557 BatchError::SenderError => {
558 warn!("Task receiver closed!");
562 state = TaskStatus::Finished;
563 break;
564 }
565 x => {
566 error!("Failed to send data!");
567 error = Some(x);
568 state = TaskStatus::Failed;
569 break;
570 }
571 }
572 }
573 }
574 Some(Err(e)) => match self.shutdown_rx.message() {
575 ShutdownMsg::Init => {
576 error!(error = %e.as_report(), "Batch task failed");
579 error = Some(e);
580 state = TaskStatus::Failed;
581 break;
582 }
583 ShutdownMsg::Abort(_) => {
584 error = Some(e);
585 state = TaskStatus::Aborted;
586 break;
587 }
588 ShutdownMsg::Cancel => {
589 state = TaskStatus::Cancelled;
590 break;
591 }
592 },
593 None => {
594 debug!("Batch task {:?} finished successfully.", self.task_id);
595 state = TaskStatus::Finished;
596 break;
597 }
598 }
599 }
600 }
601 }
602
603 let error = error.map(Arc::new);
604 self.failure.lock().clone_from(&error);
605 let err_str = error.as_ref().map(|e| e.to_report_string());
606 if let Err(e) = sender.close(error).await {
607 match e {
608 SenderError => {
609 warn!("Task receiver closed when sending None!");
613 }
614 _x => {
615 error!("Failed to close task output channel: {:?}", self.task_id);
616 state = TaskStatus::Failed;
617 }
618 }
619 }
620
621 if let Err(e) = self.change_state_notify(state, state_tx, err_str).await {
622 warn!(
623 error = %e.as_report(),
624 "The status receiver in FE has closed so the status push is failed",
625 );
626 }
627
628 self.context
629 .batch_metrics()
630 .as_ref()
631 .inspect(|m| m.batch_manager_metrics().task_num.dec());
632 }
633
634 pub fn abort(&self, err_msg: String) {
635 if self.shutdown_tx.abort(err_msg) {
638 info!("Abort task {:?} done", self.task_id);
639 } else {
640 debug!("The task has already died before this request.")
641 }
642 }
643
644 pub fn cancel(&self) {
645 if !self.shutdown_tx.cancel() {
646 debug!("The task has already died before this request.");
647 }
648 }
649
650 pub fn get_task_output(&self, output_id: &PbTaskOutputId) -> Result<TaskOutput> {
651 let task_id = TaskId::from(output_id.get_task_id()?);
652 let receiver = self.receivers.lock()[output_id.get_output_id() as usize]
653 .take()
654 .with_context(|| {
655 format!(
656 "Task{:?}'s output{} has already been taken.",
657 task_id,
658 output_id.get_output_id(),
659 )
660 })?;
661 let task_output = TaskOutput {
662 receiver,
663 output_id: output_id.try_into()?,
664 failure: self.failure.clone(),
665 };
666 Ok(task_output)
667 }
668
669 pub fn check_if_running(&self) -> Result<()> {
670 if *self.state.lock() != TaskStatus::Running {
671 bail!("task {:?} is not running", self.get_task_id());
672 }
673 Ok(())
674 }
675
676 pub fn check_if_aborted(&self) -> Result<bool> {
677 match *self.state.lock() {
678 TaskStatus::Aborted => Ok(true),
679 TaskStatus::Finished => bail!("task {:?} has been finished", self.get_task_id()),
680 _ => Ok(false),
681 }
682 }
683
684 pub fn is_end(&self) -> bool {
686 let guard = self.state.lock();
687 !(*guard == TaskStatus::Running || *guard == TaskStatus::Pending)
688 }
689}
690
691impl BatchTaskExecution {
692 pub(crate) fn set_heartbeat_join_handle(&self, join_handle: JoinHandle<()>) {
693 *self.heartbeat_join_handle.lock() = Some(join_handle);
694 }
695
696 pub(crate) fn heartbeat_join_handle(&self) -> Option<JoinHandle<()>> {
697 self.heartbeat_join_handle.lock().take()
698 }
699}
700
701#[cfg(test)]
702mod tests {
703 use super::*;
704
705 #[test]
706 fn test_task_output_id_debug() {
707 let task_id = TaskId {
708 task_id: 1,
709 stage_id: 2,
710 query_id: "abc".to_owned(),
711 };
712 let task_output_id = TaskOutputId {
713 task_id,
714 output_id: 3,
715 };
716 assert_eq!(
717 format!("{:?}", task_output_id),
718 "TaskOutputId { query_id: \"abc\", stage_id: 2, task_id: 1, output_id: 3 }"
719 );
720 }
721}