use std::sync::Arc;
use claviron_runtime::AppState;
use claviron_tasks::service::TaskService;
use claviron_tasks::{
Error as TaskError, Executor, TaskExecution, TaskExecutorKind, TaskResult,
};
use crate::config::TaskProgram;
use crate::engine::task::TaskExecutions;
use crate::service::PhpEmbedRuntime;
pub(crate) fn register(
state: &AppState,
runtime: Arc<PhpEmbedRuntime>,
) -> Result<(), String> {
let Some(tasks) = state.registry_ref().resolve::<TaskService>() else {
return Ok(());
};
tasks.set_executor(TaskExecutorKind::Php, executor(runtime));
Ok(())
}
pub(crate) fn register_bridge(
state: &AppState,
runtime: Arc<PhpEmbedRuntime>,
) -> Result<(), String> {
let Some(tasks) = state.registry_ref().resolve::<TaskService>() else {
return Ok(());
};
crate::service::invoke::register(&tasks, runtime)
}
fn executor(runtime: Arc<PhpEmbedRuntime>) -> Executor {
Arc::new(move |execution: TaskExecution| {
let runtime = Arc::clone(&runtime);
Box::pin(run(execution, runtime))
})
}
async fn run(
execution: TaskExecution,
runtime: Arc<PhpEmbedRuntime>,
) -> TaskResult<()> {
runtime
.ensure_booted()
.map_err(|error| TaskError::other(error.to_string()))?;
let TaskExecution {
task,
spec,
cancellation,
runtime: task_runtime,
graceful_timeout,
..
} = execution;
let instance = task_runtime.task_worker_number.saturating_sub(1);
let mut program = TaskProgram::new(task.clone(), spec.script.clone());
program = program.args(spec.args.iter().cloned());
program = program.log(spec.log.clone());
if let Some(cwd) = spec.cwd.as_deref() {
program = program.cwd(cwd);
}
for (key, value) in task_runtime.identity_env() {
program = program.environment(key, value);
}
for (key, value) in &spec.env {
program = program.environment(key.clone(), value.clone());
}
let mut executions = TaskExecutions::default();
executions
.start_instance(&program, instance)
.await
.map_err(TaskError::other)?;
tokio::select! {
() = cancellation.cancelled() => {}
() = executions.wait() => {}
}
let failed = executions.failed();
let deadline =
graceful_timeout.map(|grace| tokio::time::Instant::now() + grace);
executions.drain_until(deadline).await.map_err(TaskError::other)?;
if failed {
return Err(TaskError::other(format!(
"php task '{task}' ended in failure"
)));
}
Ok(())
}