use aion_core::{ActivityId, Event, RunId, WorkerAttribution, WorkflowId, WorkflowStatus};
use chrono::Utc;
use crate::EngineError;
use crate::durability::Recorder;
use crate::registry::WorkflowHandle;
use super::api::{Engine, workflow_not_found};
use super::delegated::run_has_terminal_history;
impl Engine {
pub async fn record_activity_lease(
&self,
id: &WorkflowId,
run: &RunId,
activity_id: ActivityId,
attempt: u32,
worker: WorkerAttribution,
) -> Result<(), EngineError> {
if let Some(handle) = self.registry().get(id, run)? {
return record_through_handle(&handle, activity_id, attempt, worker).await;
}
let history = self.store().read_history(id).await?;
if run_has_terminal_history(&history, run) {
return Err(lease_after_terminal(id, run, activity_id, attempt));
}
let segment = aion_core::run_segment(&history, run);
let paused = matches!(
aion_core::status_from_events(segment),
WorkflowStatus::Paused
);
let idle_workloop = match &self.workloop {
Some(workloop) => workloop.store.get_workloop(id).await?.is_some(),
None => false,
};
if paused || idle_workloop {
let head = history.last().map(Event::seq).unwrap_or_default();
let mut recorder = Recorder::resume_at(id.clone(), self.store(), head)
.with_visibility(run.clone(), self.visibility_store());
recorder
.record_activity_leased(Utc::now(), activity_id, attempt, worker)
.await?;
return Ok(());
}
let handle = self
.handle_after_birth_window(id, run, &history)
.await?
.ok_or_else(|| workflow_not_found(id, run))?;
record_through_handle(&handle, activity_id, attempt, worker).await
}
}
async fn record_through_handle(
handle: &WorkflowHandle,
activity_id: ActivityId,
attempt: u32,
worker: WorkerAttribution,
) -> Result<(), EngineError> {
let recorder = handle.recorder();
let mut recorder = recorder.lock().await;
let history = recorder.read_history().await?;
if run_has_terminal_history(&history, handle.run_id()) {
return Err(lease_after_terminal(
handle.workflow_id(),
handle.run_id(),
activity_id,
attempt,
));
}
recorder
.record_activity_leased(Utc::now(), activity_id, attempt, worker)
.await?;
Ok(())
}
fn lease_after_terminal(
id: &WorkflowId,
run: &RunId,
activity_id: ActivityId,
attempt: u32,
) -> EngineError {
EngineError::ActivityLeaseAfterTerminal {
workflow_id: id.clone(),
run_id: run.clone(),
activity_id,
attempt,
}
}