1use crate::dto::prelude::*;
2use crate::ids::BuildNetwork;
3
4pub use crate::domain::runtime::{
5 FailureSeverity, HealthStatus, ReadinessStatus, RuntimeCheckStatus, RuntimeDiagnosticSeverity,
6 RuntimeFieldVisibility, RuntimeStateDomainStatus, RuntimeStatus, TimerExecutionOutcome,
7 TimerProcessCondition, TimerRegistrationStatus, TimerSchedulingMode,
8};
9
10pub const RUNTIME_INTROSPECTION_SCHEMA_VERSION: u32 = 1;
11
12#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
17pub struct CanicHealthStatus {
18 pub schema_version: u32,
19 pub status: HealthStatus,
20 pub observed_at_ns: Option<u64>,
21 pub checks: Vec<RuntimeCheck>,
22}
23
24#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
29pub struct CanicReadinessStatus {
30 pub fixture: Result<
31 crate::dto::fixture_provisioning::FixtureProvisioningStatus,
32 crate::dto::fixture_provisioning::FixtureImportError,
33 >,
34 pub schema_version: u32,
35 pub role: Option<String>,
36 pub status: ReadinessStatus,
37 pub observed_at_ns: u64,
38 pub checks: Vec<RuntimeCheck>,
39 pub blockers: Vec<RuntimeDiagnostic>,
40 pub warnings: Vec<RuntimeDiagnostic>,
41}
42
43#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
48pub struct CanicRuntimeStatus {
49 pub schema_version: u32,
50 pub observed_at_ns: u64,
51 pub canister_id: Principal,
52 pub role: Option<String>,
53 pub root: Option<Principal>,
54 pub build_network: Option<BuildNetwork>,
55 pub build: RuntimeBuildInfo,
56 pub features: Vec<RuntimeFeatureStatus>,
57 pub topology: Option<RuntimeTopologyStatus>,
58 pub timers: Vec<CanisterTimerStatus>,
59 pub timer_inventory: RuntimeCheck,
60 pub state: Option<RuntimeStateSummary>,
61 pub auth: Option<RuntimeAuthStatusSummary>,
62 pub blob_storage: Option<RuntimeBlobStorageStatusSummary>,
63 pub receipt_capacity: Option<RuntimeReceiptCapacityStatus>,
64 pub recent_failures: Vec<RecentFailure>,
65 pub visibility: Vec<RuntimeVisibilityEntry>,
66 pub readiness: CanicReadinessStatus,
67 pub status: RuntimeStatus,
68}
69
70#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
75pub struct RuntimeBuildInfo {
76 pub package_name: String,
77 pub package_version: String,
78 pub canic_version: String,
79 pub canister_version: u64,
80}
81
82#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
87pub struct RuntimeCheck {
88 pub category: String,
89 pub code: String,
90 pub status: RuntimeCheckStatus,
91 pub subject: String,
92 pub detail: String,
93 pub next: Option<String>,
94 pub source: String,
95}
96
97#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
102pub struct RuntimeDiagnostic {
103 pub category: String,
104 pub code: String,
105 pub severity: RuntimeDiagnosticSeverity,
106 pub subject: String,
107 pub detail: String,
108 pub next: Option<String>,
109 pub source: String,
110}
111
112#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
117pub struct RuntimeFeatureStatus {
118 pub name: String,
119 pub enabled: bool,
120 pub visibility: RuntimeFieldVisibility,
121 pub source: String,
122}
123
124#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
129pub struct RuntimeTopologyStatus {
130 pub root: Option<Principal>,
131 pub parent: Option<Principal>,
132 pub subnet: Option<Principal>,
133 pub source: String,
134}
135
136#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
145pub struct CanisterTimerStatus {
146 pub name: String,
147 pub owner: String,
148 pub subsystem: String,
149 pub scheduling_mode: TimerSchedulingMode,
150 pub registration: TimerRegistrationStatus,
151 pub condition: TimerProcessCondition,
152 pub enabled: bool,
153 pub generation: Option<u64>,
154 pub next_due_at_ns: Option<u64>,
155 pub last_outcome: Option<TimerExecutionOutcome>,
156 pub last_work_count: u64,
157 pub last_success_at_ns: Option<u64>,
158 pub last_failure_at_ns: Option<u64>,
159 pub consecutive_expected_failures: u64,
160 pub schedules_since_runtime_start: u64,
161 pub executions_since_runtime_start: u64,
162 pub successes_since_runtime_start: u64,
163 pub expected_failures_since_runtime_start: u64,
164 pub invariant_failures_since_runtime_start: u64,
165 pub stale_callbacks_since_runtime_start: u64,
166 pub scheduler_performance: TimerCallbackPerformanceStatus,
167 pub work_performance: TimerCallbackPerformanceStatus,
168}
169
170#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
179pub struct TimerCallbackPerformanceStatus {
180 pub instruction_samples_since_runtime_start: u64,
181 pub instructions_latest: Option<u64>,
182 pub instructions_maximum: Option<u64>,
183 pub instructions_total_since_runtime_start: u64,
184 pub memory_page_samples_since_runtime_start: u64,
185 pub memory_pages_latest: Option<TimerMemoryPageSampleStatus>,
186 pub maximum_wasm_memory_growth_pages: Option<u64>,
187 pub maximum_stable_memory_growth_pages: Option<u64>,
188}
189
190#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
196pub struct TimerMemoryPageSampleStatus {
197 pub start: TimerMemoryPageExtentStatus,
198 pub end: TimerMemoryPageExtentStatus,
199}
200
201#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
207pub struct TimerMemoryPageExtentStatus {
208 pub wasm_pages: u64,
209 pub stable_pages: u64,
210}
211
212#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
217pub struct RuntimeStateSummary {
218 pub manifest_schema_version: u32,
219 pub domains: Vec<RuntimeStateDomainSummary>,
220 pub total_stable_memory_pages: Option<u64>,
221}
222
223#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
228pub struct RuntimeStateDomainSummary {
229 pub domain: String,
230 pub version: u32,
231 pub storage: String,
232 pub memory_id: Option<u8>,
233 pub status: RuntimeStateDomainStatus,
234}
235
236#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
241pub struct RuntimeAuthStatusSummary {
242 pub auth_features: Vec<RuntimeFeatureStatus>,
243}
244
245#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
250pub struct RuntimeBlobStorageStatusSummary {
251 pub blob_storage_features: Vec<RuntimeFeatureStatus>,
252}
253
254#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
259pub struct RuntimeReceiptCapacityStatus {
260 pub status: RuntimeCheckStatus,
261 pub receipt_records: u64,
262 pub application_receipt_records: u64,
263 pub canic_owned_receipt_records: u64,
264 pub pending_application_receipt_records: u64,
265 pub terminal_application_receipt_records: u64,
266 pub receipt_record_limit: u64,
267 pub remaining_receipt_record_headroom: u64,
268 pub resource_total_records: u64,
269 pub resource_total_record_limit: u64,
270 pub remaining_resource_total_headroom: u64,
271 pub warning_headroom_threshold: u64,
272 pub reserved_terminal_slots: u64,
273 pub reserved_terminal_pages: u64,
274 pub next_terminal_eligibility_at_ns: Option<u64>,
275 pub source: String,
276}
277
278#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
283pub struct RecentFailure {
284 pub occurred_at_ns: u64,
285 pub subsystem: String,
286 pub code: String,
287 pub severity: FailureSeverity,
288 pub summary: String,
289 pub correlation_id: Option<String>,
290 pub redacted: bool,
291}
292
293#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
298pub struct RuntimeVisibilityEntry {
299 pub field: String,
300 pub visibility: RuntimeFieldVisibility,
301}
302
303#[cfg(test)]
304mod tests {
305 use super::*;
306 use candid::{Decode, Encode};
307 use serde::Serialize;
308 use serde::de::DeserializeOwned;
309 use std::fmt::Debug;
310
311 #[test]
312 fn runtime_enums_roundtrip_candid_with_canonical_variant_labels() {
313 assert_enum_candid_contract(HealthStatus::Unknown);
314 assert_enum_candid_contract(ReadinessStatus::NotEvaluated);
315 assert_enum_candid_contract(RuntimeStatus::Failing);
316 assert_enum_candid_contract(TimerRegistrationStatus::Unregistered);
317 assert_enum_candid_contract(TimerProcessCondition::MissingRegistration);
318 assert_enum_candid_contract(TimerSchedulingMode::AfterCompletion);
319 assert_enum_candid_contract(TimerExecutionOutcome::InvariantFailure);
320 assert_enum_candid_contract(FailureSeverity::Critical);
321 assert_enum_candid_contract(RuntimeCheckStatus::NotEvaluated);
322 assert_enum_candid_contract(RuntimeDiagnosticSeverity::Unsupported);
323 assert_enum_candid_contract(RuntimeFieldVisibility::OperatorOnly);
324 assert_enum_candid_contract(RuntimeStateDomainStatus::NotEvaluated);
325 }
326
327 #[test]
328 fn runtime_enums_serialize_canonical_snake_case_labels() {
329 assert_enum_serde_contract(HealthStatus::Healthy, HealthStatus::Healthy.label());
330 assert_enum_serde_contract(HealthStatus::Degraded, HealthStatus::Degraded.label());
331 assert_enum_serde_contract(HealthStatus::Unhealthy, HealthStatus::Unhealthy.label());
332 assert_enum_serde_contract(HealthStatus::Unknown, HealthStatus::Unknown.label());
333
334 assert_enum_serde_contract(ReadinessStatus::Ready, ReadinessStatus::Ready.label());
335 assert_enum_serde_contract(ReadinessStatus::Degraded, ReadinessStatus::Degraded.label());
336 assert_enum_serde_contract(ReadinessStatus::NotReady, ReadinessStatus::NotReady.label());
337 assert_enum_serde_contract(
338 ReadinessStatus::NotEvaluated,
339 ReadinessStatus::NotEvaluated.label(),
340 );
341
342 assert_enum_serde_contract(RuntimeStatus::Ok, RuntimeStatus::Ok.label());
343 assert_enum_serde_contract(RuntimeStatus::Degraded, RuntimeStatus::Degraded.label());
344 assert_enum_serde_contract(RuntimeStatus::Failing, RuntimeStatus::Failing.label());
345 assert_enum_serde_contract(RuntimeStatus::Unknown, RuntimeStatus::Unknown.label());
346
347 assert_enum_serde_contract(
348 TimerRegistrationStatus::Unregistered,
349 TimerRegistrationStatus::Unregistered.label(),
350 );
351 assert_enum_serde_contract(
352 TimerProcessCondition::MissingRegistration,
353 TimerProcessCondition::MissingRegistration.label(),
354 );
355 assert_enum_serde_contract(
356 TimerSchedulingMode::AfterCompletion,
357 TimerSchedulingMode::AfterCompletion.label(),
358 );
359 assert_enum_serde_contract(
360 TimerExecutionOutcome::InvariantFailure,
361 TimerExecutionOutcome::InvariantFailure.label(),
362 );
363
364 assert_enum_serde_contract(FailureSeverity::Info, FailureSeverity::Info.label());
365 assert_enum_serde_contract(FailureSeverity::Warning, FailureSeverity::Warning.label());
366 assert_enum_serde_contract(FailureSeverity::Error, FailureSeverity::Error.label());
367 assert_enum_serde_contract(FailureSeverity::Critical, FailureSeverity::Critical.label());
368
369 assert_enum_serde_contract(RuntimeCheckStatus::Pass, RuntimeCheckStatus::Pass.label());
370 assert_enum_serde_contract(RuntimeCheckStatus::Warn, RuntimeCheckStatus::Warn.label());
371 assert_enum_serde_contract(RuntimeCheckStatus::Fail, RuntimeCheckStatus::Fail.label());
372 assert_enum_serde_contract(
373 RuntimeCheckStatus::NotEvaluated,
374 RuntimeCheckStatus::NotEvaluated.label(),
375 );
376
377 assert_enum_serde_contract(
378 RuntimeDiagnosticSeverity::Info,
379 RuntimeDiagnosticSeverity::Info.label(),
380 );
381 assert_enum_serde_contract(
382 RuntimeDiagnosticSeverity::Warning,
383 RuntimeDiagnosticSeverity::Warning.label(),
384 );
385 assert_enum_serde_contract(
386 RuntimeDiagnosticSeverity::Blocked,
387 RuntimeDiagnosticSeverity::Blocked.label(),
388 );
389 assert_enum_serde_contract(
390 RuntimeDiagnosticSeverity::Unsupported,
391 RuntimeDiagnosticSeverity::Unsupported.label(),
392 );
393
394 assert_enum_serde_contract(
395 RuntimeFieldVisibility::PublicSafe,
396 RuntimeFieldVisibility::PublicSafe.label(),
397 );
398 assert_enum_serde_contract(
399 RuntimeFieldVisibility::OperatorOnly,
400 RuntimeFieldVisibility::OperatorOnly.label(),
401 );
402 assert_enum_serde_contract(
403 RuntimeFieldVisibility::ControllerOnly,
404 RuntimeFieldVisibility::ControllerOnly.label(),
405 );
406 assert_enum_serde_contract(
407 RuntimeFieldVisibility::FeatureGated,
408 RuntimeFieldVisibility::FeatureGated.label(),
409 );
410 assert_enum_serde_contract(
411 RuntimeFieldVisibility::Disabled,
412 RuntimeFieldVisibility::Disabled.label(),
413 );
414
415 assert_enum_serde_contract(
416 RuntimeStateDomainStatus::Ok,
417 RuntimeStateDomainStatus::Ok.label(),
418 );
419 assert_enum_serde_contract(
420 RuntimeStateDomainStatus::Warning,
421 RuntimeStateDomainStatus::Warning.label(),
422 );
423 assert_enum_serde_contract(
424 RuntimeStateDomainStatus::Failing,
425 RuntimeStateDomainStatus::Failing.label(),
426 );
427 assert_enum_serde_contract(
428 RuntimeStateDomainStatus::NotEvaluated,
429 RuntimeStateDomainStatus::NotEvaluated.label(),
430 );
431 }
432
433 fn assert_enum_candid_contract<T>(value: T)
434 where
435 T: CandidType + Clone + Debug + DeserializeOwned + Eq,
436 {
437 let bytes = Encode!(&value).expect("encode runtime enum");
438 let decoded = Decode!(&bytes, T).expect("decode runtime enum");
439
440 assert_eq!(decoded, value);
441 }
442
443 fn assert_enum_serde_contract<T>(value: T, label: &str)
444 where
445 T: Clone + Debug + DeserializeOwned + Eq + Serialize,
446 {
447 let encoded = crate::cdk::serialize::serialize(&value).expect("encode runtime enum label");
448 let serialized_label: String =
449 crate::cdk::serialize::deserialize(&encoded).expect("decode runtime enum label");
450 assert_eq!(serialized_label, label);
451
452 let label_bytes =
453 crate::cdk::serialize::serialize(&label).expect("encode canonical runtime enum label");
454 let decoded: T = crate::cdk::serialize::deserialize(&label_bytes)
455 .expect("decode canonical runtime enum label");
456 assert_eq!(decoded, value);
457 }
458}