pub mod query;
use crate::{
InternalError, InternalErrorOrigin,
domain::policy::placement::scaling::{ScalingPlan, ScalingPolicy},
ops::{
config::ConfigOps,
ic::IcOps,
rpc::request::{CreateCanisterParent, RequestOps},
storage::placement::scaling::ScalingRegistryOps,
},
workflow::prelude::*,
};
pub struct ScalingWorkflow;
impl ScalingWorkflow {
pub(crate) async fn create_worker(pool: &str) -> Result<Principal, InternalError> {
let worker_count = ScalingRegistryOps::count_by_pool(pool);
let scaling = ConfigOps::current_scaling_config()?;
crate::perf!("observe_state");
let ScalingPlan {
should_spawn,
reason,
worker_entry,
} = ScalingPolicy::plan_create_worker(pool, worker_count, scaling)?;
crate::perf!("plan_spawn");
if !should_spawn {
return Err(InternalError::domain(InternalErrorOrigin::Workflow, reason));
}
let entry_plan = worker_entry.ok_or_else(|| {
InternalError::invariant(
InternalErrorOrigin::Workflow,
"worker entry missing for spawn plan",
)
})?;
let role = entry_plan.canister_role.clone();
let pid =
RequestOps::create_canister::<()>(&role, CreateCanisterParent::ThisCanister, None)
.await?
.new_canister_pid;
crate::perf!("create_canister");
let created_at_secs = IcOps::now_secs();
ScalingRegistryOps::upsert_from_plan(pid, entry_plan, created_at_secs);
crate::perf!("register_worker");
Ok(pid)
}
pub(crate) fn plan_create_worker(pool: &str) -> Result<bool, InternalError> {
let worker_count = ScalingRegistryOps::count_by_pool(pool);
let scaling = ConfigOps::current_scaling_config()?;
crate::perf!("observe_state");
let plan = ScalingPolicy::plan_create_worker(pool, worker_count, scaling)?;
crate::perf!("plan_spawn");
Ok(plan.should_spawn)
}
}