made_core/entities/ceremony_instance/
step_execution.rs1use crate::entities::ceremony_commands::{ApplyStepResult, StartStep};
2use crate::entities::CeremonyCommand;
3use crate::value_objects::{MaxParallel, StepClaimFence};
4
5use super::{
6 CeremonyDefinition, CeremonyEvent, CeremonyInstance, DomainError, OffsetDateTime, RoleId,
7 StepAttempt, StepId, StepLease, StepResult,
8};
9
10impl CeremonyInstance {
14 pub fn start_step_as(
15 &mut self,
16 definition: &CeremonyDefinition,
17 role_id: &RoleId,
18 step_id: &StepId,
19 lease: StepLease,
20 now: OffsetDateTime,
21 ) -> Result<StepAttempt, DomainError> {
22 self.start_step_with(
23 definition,
24 Some(role_id.clone()),
25 step_id,
26 lease,
27 now,
28 MaxParallel::SERVER_MAX,
29 )
30 }
31
32 pub fn start_step(
33 &mut self,
34 definition: &CeremonyDefinition,
35 step_id: &StepId,
36 lease: StepLease,
37 now: OffsetDateTime,
38 ) -> Result<StepAttempt, DomainError> {
39 self.start_step_with(
40 definition,
41 None,
42 step_id,
43 lease,
44 now,
45 MaxParallel::SERVER_MAX,
46 )
47 }
48
49 fn start_step_with(
50 &mut self,
51 definition: &CeremonyDefinition,
52 role_id: Option<RoleId>,
53 step_id: &StepId,
54 lease: StepLease,
55 now: OffsetDateTime,
56 max_parallel_ceiling: MaxParallel,
57 ) -> Result<StepAttempt, DomainError> {
58 let command = CeremonyCommand::StartStep(StartStep {
59 role_id,
60 step_id: step_id.clone(),
61 lease,
62 now,
63 max_parallel_ceiling,
64 budget_reservation_id: None,
65 });
66 let events = self.decide(&command, definition)?;
67 let attempt = events
68 .iter()
69 .find_map(|event| match event {
70 CeremonyEvent::StepStarted(started) => Some(started.attempt),
71 _ => None,
72 })
73 .ok_or(DomainError::InvariantViolated {
74 reason: "starting a step decides a step start",
75 })?;
76 self.apply_all(&events);
77 Ok(attempt)
78 }
79
80 pub fn step_claim_fence(&self, step_id: &StepId) -> Result<StepClaimFence, DomainError> {
82 let record = self.step_record(step_id).ok_or(DomainError::NotFound {
83 what: "ceremony_instance.step_record",
84 })?;
85 StepClaimFence::for_record(self.id(), step_id, record)
86 }
87
88 pub(super) fn require_step_claim_fence(
89 &self,
90 step_id: &StepId,
91 fence: &StepClaimFence,
92 ) -> Result<(), DomainError> {
93 if &self.step_claim_fence(step_id)? != fence {
94 return Err(DomainError::InvariantViolated {
95 reason: "step completion claim fence does not match the current claim",
96 });
97 }
98 Ok(())
99 }
100
101 pub fn apply_step_result(
102 &mut self,
103 definition: &CeremonyDefinition,
104 step_id: &StepId,
105 claim_fence: StepClaimFence,
106 result: StepResult,
107 now: OffsetDateTime,
108 ) -> Result<(), DomainError> {
109 let command = CeremonyCommand::ApplyStepResult(ApplyStepResult {
110 step_id: step_id.clone(),
111 claim_fence,
112 result,
113 now,
114 });
115 let events = self.decide(&command, definition)?;
116 self.apply_all(&events);
117 Ok(())
118 }
119}