canic_core/workflow/placement/
scaling.rs1use crate::{
11 Error, ThisError,
12 cdk::utils::time::now_secs,
13 dto::rpc::CreateCanisterParent,
14 ops::rpc::create_canister_request,
15 ops::{adapter::placement::worker_entry_from_view, storage::scaling::ScalingRegistryOps},
16 policy::placement::scaling::{ScalingPlan, ScalingPolicy},
17};
18use candid::Principal;
19
20#[derive(Debug, ThisError)]
26pub enum ScalingWorkflowError {
27 #[error("scaling plan rejected: {0}")]
28 PlanRejected(String),
29}
30
31impl From<ScalingWorkflowError> for Error {
32 fn from(err: ScalingWorkflowError) -> Self {
33 Self::WorkflowError(err.to_string())
34 }
35}
36
37pub struct ScalingWorkflow;
41
42impl ScalingWorkflow {
43 pub async fn create_worker(pool: &str) -> Result<Principal, Error> {
45 let ScalingPlan {
47 should_spawn,
48 reason,
49 worker_entry,
50 } = ScalingPolicy::plan_create_worker(pool, now_secs())?;
51
52 if !should_spawn {
53 return Err(ScalingWorkflowError::PlanRejected(reason))?;
54 }
55
56 let entry_view = worker_entry.ok_or_else(|| {
57 ScalingWorkflowError::PlanRejected("worker entry missing for spawn plan".to_string())
58 })?;
59
60 let role = entry_view.canister_role.clone();
61
62 let pid = create_canister_request::<()>(&role, CreateCanisterParent::ThisCanister, None)
64 .await?
65 .new_canister_pid;
66
67 let entry = worker_entry_from_view(entry_view);
69 ScalingRegistryOps::upsert(pid, entry);
70
71 Ok(pid)
72 }
73}