mod spawn;
mod validate;
use std::sync::Arc;
use crate::env::stream_env::StreamEnv;
use crate::runtime::checkpoint_manager::CheckpointManager;
use crate::runtime::job_runtime::{ChainJobRuntime, shutdown_chain_job};
use crate::runtime::task_lifecycle::report_task_failure;
use tinyflow_api::error::StreamResult;
pub use spawn::spawn_chained_tasks;
use spawn::spawn_chained_tasks as spawn_tasks;
use validate::resolve_job_state_for_execute;
pub async fn execute(env: StreamEnv) -> StreamResult<()> {
let (job_state, work_dir) = resolve_job_state_for_execute(&env).await?;
let work_dir_ref = work_dir.as_deref();
{
let pending = std::mem::take(&mut *env.pending_job_state.lock().unwrap());
for (namespace, key, value) in pending {
job_state.put(&namespace, key.as_bytes(), &value).await?;
}
}
let (ack_tx, ack_rx) = tokio::sync::mpsc::channel(64);
let (error_tx, mut error_rx) = tokio::sync::mpsc::channel(64);
let job_runtime = ChainJobRuntime::new();
let mut task_id_counter = 0u32;
let pending = spawn_tasks(
&env,
job_state,
work_dir_ref,
&job_runtime,
&ack_tx,
&error_tx,
0,
&mut task_id_counter,
)
.await?;
for p in pending {
job_runtime.register_join(p.spawn());
}
let cm_handle = if env.checkpoint_interval_ms > 0
&& !job_runtime.control_senders.lock().unwrap().is_empty()
{
let interval = env.checkpoint_interval_ms;
log::info!(
"[execute] checkpoint manager interval={}ms, {} tasks",
interval,
job_runtime.control_senders.lock().unwrap().len()
);
let mut cm =
CheckpointManager::new(interval, ack_rx, Arc::clone(&job_runtime.control_senders));
let cm_error_tx = error_tx.clone();
Some(tokio::spawn(async move {
if let Err(e) = cm.run().await {
report_task_failure(&cm_error_tx, 0, "checkpoint-manager", e).await;
}
}))
} else {
drop(ack_rx);
None
};
drop(ack_tx);
let result = if let Some(handle) = cm_handle {
tokio::select! {
_ = tokio::signal::ctrl_c() => Ok(()),
msg = error_rx.recv() => match msg {
Some(e) => Err(e),
None => Ok(()),
},
_ = handle => match error_rx.try_recv() {
Ok(e) => Err(e),
Err(_) => Ok(()),
},
}
} else {
tokio::select! {
_ = tokio::signal::ctrl_c() => Ok(()),
msg = error_rx.recv() => match msg {
Some(e) => Err(e),
None => Ok(()),
},
}
};
shutdown_chain_job(&job_runtime).await?;
result
}