use super::{BuildTask, ConsolidateTask, FinalizeTask, InsertTask};
use crate::{
BuildTaskError, ConsolidateTaskError, EngineState, FinalizeTaskError, InsertTaskError,
};
use async_trait::async_trait;
use derive_more::Display;
use std::cmp::Ordering;
use thiserror::Error;
#[derive(Debug, PartialEq, Eq, Display, Clone, Copy)]
pub enum EngineTaskErrorSeverity {
#[display("temporary")]
Temporary,
#[display("critical")]
Critical,
#[display("reset")]
Reset,
#[display("flush")]
Flush,
}
pub trait EngineTaskError {
fn severity(&self) -> EngineTaskErrorSeverity;
}
#[async_trait]
pub trait EngineTaskExt {
type Output;
type Error: EngineTaskError;
async fn execute(&self, state: &mut EngineState) -> Result<Self::Output, Self::Error>;
}
#[derive(Error, Debug)]
pub enum EngineTaskErrors {
#[error(transparent)]
Insert(#[from] InsertTaskError),
#[error(transparent)]
Build(#[from] BuildTaskError),
#[error(transparent)]
Consolidate(#[from] ConsolidateTaskError),
#[error(transparent)]
Finalize(#[from] FinalizeTaskError),
}
impl EngineTaskError for EngineTaskErrors {
fn severity(&self) -> EngineTaskErrorSeverity {
match self {
Self::Insert(inner) => inner.severity(),
Self::Build(inner) => inner.severity(),
Self::Consolidate(inner) => inner.severity(),
Self::Finalize(inner) => inner.severity(),
}
}
}
#[derive(Debug, Clone)]
pub enum EngineTask {
Insert(InsertTask),
Build(BuildTask),
Consolidate(ConsolidateTask),
Finalize(FinalizeTask),
}
impl EngineTask {
async fn execute_inner(&self, state: &mut EngineState) -> Result<(), EngineTaskErrors> {
match self.clone() {
Self::Insert(task) => task.execute(state).await?,
Self::Build(task) => task.execute(state).await?,
Self::Consolidate(task) => task.execute(state).await?,
Self::Finalize(task) => task.execute(state).await?,
};
Ok(())
}
const fn task_metrics_label(&self) -> &'static str {
match self {
Self::Insert(_) => crate::Metrics::INSERT_TASK_LABEL,
Self::Consolidate(_) => crate::Metrics::CONSOLIDATE_TASK_LABEL,
Self::Build(_) => crate::Metrics::BUILD_TASK_LABEL,
Self::Finalize(_) => crate::Metrics::FINALIZE_TASK_LABEL,
}
}
}
impl PartialEq for EngineTask {
fn eq(&self, other: &Self) -> bool {
matches!(
(self, other),
(Self::Insert(_), Self::Insert(_)) |
(Self::Build(_), Self::Build(_)) |
(Self::Consolidate(_), Self::Consolidate(_)) |
(Self::Finalize(_), Self::Finalize(_))
)
}
}
impl Eq for EngineTask {}
impl PartialOrd for EngineTask {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for EngineTask {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Self::Insert(_), Self::Insert(_)) => Ordering::Equal,
(Self::Consolidate(_), Self::Consolidate(_)) => Ordering::Equal,
(Self::Build(_), Self::Build(_)) => Ordering::Equal,
(Self::Finalize(_), Self::Finalize(_)) => Ordering::Equal,
(Self::Build(_), _) => Ordering::Greater,
(_, Self::Build(_)) => Ordering::Less,
(Self::Insert(_), _) => Ordering::Greater,
(_, Self::Insert(_)) => Ordering::Less,
(Self::Consolidate(_), _) => Ordering::Greater,
(_, Self::Consolidate(_)) => Ordering::Less,
}
}
}
#[async_trait]
impl EngineTaskExt for EngineTask {
type Output = ();
type Error = EngineTaskErrors;
async fn execute(&self, state: &mut EngineState) -> Result<(), Self::Error> {
while let Err(e) = self.execute_inner(state).await {
let severity = e.severity();
kona_macros::inc!(
counter,
crate::Metrics::ENGINE_TASK_FAILURE,
self.task_metrics_label() => severity.to_string()
);
match severity {
EngineTaskErrorSeverity::Temporary => {
trace!(target: "engine", "{e}");
continue;
}
EngineTaskErrorSeverity::Critical => {
error!(target: "engine", "{e}");
return Err(e);
}
EngineTaskErrorSeverity::Reset => {
warn!(target: "engine", "Engine requested derivation reset");
return Err(e);
}
EngineTaskErrorSeverity::Flush => {
warn!(target: "engine", "Engine requested derivation flush");
return Err(e);
}
}
}
kona_macros::inc!(counter, crate::Metrics::ENGINE_TASK_SUCCESS, self.task_metrics_label());
Ok(())
}
}