use std::str::FromStr;
use cloacina_workflow_plugin::fidius::PluginError;
use cloacina_workflow_plugin::CloacinaHost;
use tokio::runtime::Handle;
use super::deferral_registry;
use crate::database::universal_types::UniversalUuid;
pub struct EngineHost;
impl EngineHost {
fn parse_id(raw: &str) -> Result<UniversalUuid, PluginError> {
uuid::Uuid::from_str(raw)
.map(UniversalUuid::from)
.map_err(|e| PluginError::new("BAD_TASK_ID", format!("malformed task id {raw:?}: {e}")))
}
fn entry(raw: &str) -> Result<deferral_registry::DeferralEntry, PluginError> {
let id = Self::parse_id(raw)?;
deferral_registry::lookup(&id).ok_or_else(|| {
PluginError::new(
"TASK_NOT_RUNNING",
format!("no running task registered for {raw} — it may have already completed"),
)
})
}
}
impl CloacinaHost for EngineHost {
fn release_slot(&self, task_execution_id: String) -> Result<(), PluginError> {
let entry = Self::entry(&task_execution_id)?;
Handle::current().block_on(async move {
entry.slot.lock().await.release();
});
Ok(())
}
fn reclaim_slot(&self, task_execution_id: String) -> Result<(), PluginError> {
let entry = Self::entry(&task_execution_id)?;
Handle::current().block_on(async move {
entry.slot.lock().await.reclaim().await.map_err(|e| {
PluginError::new("SLOT_RECLAIM_FAILED", format!("{e}"))
})
})
}
fn set_sub_status(
&self,
task_execution_id: String,
sub_status: String,
) -> Result<(), PluginError> {
let id = Self::parse_id(&task_execution_id)?;
let entry = Self::entry(&task_execution_id)?;
let value = if sub_status.is_empty() {
None
} else {
Some(sub_status)
};
Handle::current().block_on(async move {
entry
.dal
.task_execution()
.set_sub_status(id, value.as_deref())
.await
.map_err(|e| PluginError::new("SUB_STATUS_FAILED", format!("{e}")))
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn unknown_task_is_a_typed_error() {
let host = EngineHost;
let err = host
.release_slot(uuid::Uuid::new_v4().to_string())
.expect_err("unknown task must error");
assert_eq!(err.code, "TASK_NOT_RUNNING");
}
#[tokio::test]
async fn malformed_task_id_is_rejected() {
let host = EngineHost;
let err = host
.release_slot("not-a-uuid".to_string())
.expect_err("malformed id must error");
assert_eq!(err.code, "BAD_TASK_ID");
}
}