use aion_core::{Event, Payload, RunId, TimerCancelCause, TimerId};
use chrono::{DateTime, Utc};
use super::{Recorder, WorkflowStartRecord};
use crate::durability::DurabilityError;
pub struct ContinuationTerminal {
pub input: Payload,
pub workflow_type: Option<String>,
}
pub struct ContinuedGeneration {
pub run_id: RunId,
pub terminal: Option<ContinuationTerminal>,
pub outstanding_deadline: Option<TimerId>,
}
pub struct OpeningGeneration {
pub start: WorkflowStartRecord,
pub deadline: Option<(TimerId, DateTime<Utc>)>,
}
impl Recorder {
pub async fn record_continue_as_new_boundary(
&mut self,
recorded_at: DateTime<Utc>,
continued: ContinuedGeneration,
opening: OpeningGeneration,
) -> Result<Option<(TimerId, DateTime<Utc>, u64)>, DurabilityError> {
let ContinuedGeneration {
run_id: parent_run_id,
terminal,
outstanding_deadline,
} = continued;
let OpeningGeneration { start, deadline } = opening;
let WorkflowStartRecord {
workflow_type: successor_type,
input: successor_input,
run_id,
parent_run_id: successor_parent_run,
parent_workflow_id,
package_version,
} = start;
let successor_run_id = run_id.clone();
let mut envelope = self.next_envelope(recorded_at)?;
let mut batch = Vec::with_capacity(4);
if let Some(ContinuationTerminal {
input,
workflow_type,
}) = terminal
{
batch.push(Event::WorkflowContinuedAsNew {
envelope: envelope.clone(),
input,
workflow_type,
parent_run_id,
});
envelope = self.envelope_after(&envelope, recorded_at)?;
}
if let Some(deadline_id) = outstanding_deadline {
batch.push(Event::TimerCancelled {
envelope: envelope.clone(),
timer_id: deadline_id,
cause: TimerCancelCause::WorkflowIntent,
});
envelope = self.envelope_after(&envelope, recorded_at)?;
}
batch.push(Event::WorkflowStarted {
envelope: envelope.clone(),
workflow_type: successor_type,
input: successor_input,
run_id,
parent_run_id: successor_parent_run,
parent_workflow_id,
package_version,
});
let armed = match deadline {
Some((deadline_id, fire_at)) => {
let envelope = self.envelope_after(&envelope, recorded_at)?;
let armed_seq = envelope.seq;
batch.push(Event::TimerStarted {
envelope,
timer_id: deadline_id.clone(),
fire_at,
});
Some((deadline_id, fire_at, armed_seq))
}
None => None,
};
self.durable_append(&batch).await?;
self.follow_generation(successor_run_id).await;
Ok(armed)
}
async fn follow_generation(&mut self, successor_run_id: RunId) {
self.upsert_visibility_projection_nonfatal().await;
self.run_id = Some(successor_run_id.clone());
self.retarget_visibility(successor_run_id);
self.upsert_visibility_projection_nonfatal().await;
}
pub async fn record_workloop_iteration_boundary(
&mut self,
recorded_at: DateTime<Utc>,
routes: Vec<String>,
health_samples: Vec<aion_core::HealthSample>,
carry: Payload,
parent_run_id: RunId,
successor: WorkflowStartRecord,
) -> Result<(), DurabilityError> {
let closed_envelope = self.next_envelope(recorded_at)?;
let continued_envelope = self.envelope_after(&closed_envelope, recorded_at)?;
let started_envelope = self.envelope_after(&continued_envelope, recorded_at)?;
let WorkflowStartRecord {
workflow_type,
input,
run_id,
parent_run_id: successor_parent_run,
parent_workflow_id,
package_version,
} = successor;
let recorded_run_id = run_id.clone();
let batch = [
Event::IterationClosed {
envelope: closed_envelope,
routes,
health_samples,
},
Event::WorkflowContinuedAsNew {
envelope: continued_envelope,
input: carry,
workflow_type: None,
parent_run_id,
},
Event::WorkflowStarted {
envelope: started_envelope,
workflow_type,
input,
run_id,
parent_run_id: successor_parent_run,
parent_workflow_id,
package_version,
},
];
self.durable_append(&batch).await?;
self.follow_generation(recorded_run_id).await;
Ok(())
}
pub async fn record_workloop_retirement_generation(
&mut self,
recorded_at: DateTime<Utc>,
carry: Payload,
parent_run_id: RunId,
retirement: WorkflowStartRecord,
) -> Result<(), DurabilityError> {
let continued_envelope = self.next_envelope(recorded_at)?;
let started_envelope = self.envelope_after(&continued_envelope, recorded_at)?;
let WorkflowStartRecord {
workflow_type,
input,
run_id,
parent_run_id: retirement_parent_run,
parent_workflow_id,
package_version,
} = retirement;
let recorded_run_id = run_id.clone();
let batch = [
Event::WorkflowContinuedAsNew {
envelope: continued_envelope,
input: carry,
workflow_type: None,
parent_run_id,
},
Event::WorkflowStarted {
envelope: started_envelope,
workflow_type,
input,
run_id,
parent_run_id: retirement_parent_run,
parent_workflow_id,
package_version,
},
];
self.durable_append(&batch).await?;
self.follow_generation(recorded_run_id).await;
Ok(())
}
}