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 = 3;
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 schema_version: u32,
31 pub role: Option<String>,
32 pub status: ReadinessStatus,
33 pub observed_at_ns: u64,
34 pub checks: Vec<RuntimeCheck>,
35 pub blockers: Vec<RuntimeDiagnostic>,
36 pub warnings: Vec<RuntimeDiagnostic>,
37}
38
39#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
44pub struct CanicRuntimeStatus {
45 pub schema_version: u32,
46 pub observed_at_ns: u64,
47 pub canister_id: Principal,
48 pub role: Option<String>,
49 pub root: Option<Principal>,
50 pub build_network: Option<BuildNetwork>,
51 pub build: RuntimeBuildInfo,
52 pub features: Vec<RuntimeFeatureStatus>,
53 pub topology: Option<RuntimeTopologyStatus>,
54 pub timers: Vec<CanisterTimerStatus>,
55 pub timer_inventory: RuntimeCheck,
56 pub state: Option<RuntimeStateSummary>,
57 pub auth: Option<RuntimeAuthStatusSummary>,
58 pub blob_storage: Option<RuntimeBlobStorageStatusSummary>,
59 pub receipt_capacity: Option<RuntimeReceiptCapacityStatus>,
60 pub recent_failures: Vec<RecentFailure>,
61 pub visibility: Vec<RuntimeVisibilityEntry>,
62 pub readiness: CanicReadinessStatus,
63 pub status: RuntimeStatus,
64}
65
66#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
71pub struct RuntimeBuildInfo {
72 pub package_name: String,
73 pub package_version: String,
74 pub canic_version: String,
75 pub canister_version: u64,
76}
77
78#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
83pub struct RuntimeCheck {
84 pub category: String,
85 pub code: String,
86 pub status: RuntimeCheckStatus,
87 pub subject: String,
88 pub detail: String,
89 pub next: Option<String>,
90 pub source: String,
91}
92
93#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
98pub struct RuntimeDiagnostic {
99 pub category: String,
100 pub code: String,
101 pub severity: RuntimeDiagnosticSeverity,
102 pub subject: String,
103 pub detail: String,
104 pub next: Option<String>,
105 pub source: String,
106}
107
108#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
113pub struct RuntimeFeatureStatus {
114 pub name: String,
115 pub enabled: bool,
116 pub visibility: RuntimeFieldVisibility,
117 pub source: String,
118}
119
120#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
125pub struct RuntimeTopologyStatus {
126 pub root: Option<Principal>,
127 pub parent: Option<Principal>,
128 pub subnet: Option<Principal>,
129 pub source: String,
130}
131
132#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
141pub struct CanisterTimerStatus {
142 pub name: String,
143 pub owner: String,
144 pub subsystem: String,
145 pub scheduling_mode: TimerSchedulingMode,
146 pub registration: TimerRegistrationStatus,
147 pub condition: TimerProcessCondition,
148 pub enabled: bool,
149 pub generation: Option<u64>,
150 pub next_due_at_ns: Option<u64>,
151 pub last_outcome: Option<TimerExecutionOutcome>,
152 pub last_work_count: u64,
153 pub last_success_at_ns: Option<u64>,
154 pub last_failure_at_ns: Option<u64>,
155 pub consecutive_expected_failures: u64,
156 pub schedules_since_runtime_start: u64,
157 pub executions_since_runtime_start: u64,
158 pub successes_since_runtime_start: u64,
159 pub expected_failures_since_runtime_start: u64,
160 pub invariant_failures_since_runtime_start: u64,
161 pub stale_callbacks_since_runtime_start: u64,
162 pub scheduler_performance: TimerCallbackPerformanceStatus,
163 pub work_performance: TimerCallbackPerformanceStatus,
164}
165
166#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
175pub struct TimerCallbackPerformanceStatus {
176 pub instruction_samples_since_runtime_start: u64,
177 pub instructions_latest: Option<u64>,
178 pub instructions_maximum: Option<u64>,
179 pub instructions_total_since_runtime_start: u64,
180 pub memory_page_samples_since_runtime_start: u64,
181 pub memory_pages_latest: Option<TimerMemoryPageSampleStatus>,
182 pub maximum_wasm_memory_growth_pages: Option<u64>,
183 pub maximum_stable_memory_growth_pages: Option<u64>,
184}
185
186#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
192pub struct TimerMemoryPageSampleStatus {
193 pub start: TimerMemoryPageExtentStatus,
194 pub end: TimerMemoryPageExtentStatus,
195}
196
197#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
203pub struct TimerMemoryPageExtentStatus {
204 pub wasm_pages: u64,
205 pub stable_pages: u64,
206}
207
208#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
213pub struct RuntimeStateSummary {
214 pub manifest_schema_version: u32,
215 pub domains: Vec<RuntimeStateDomainSummary>,
216 pub total_stable_memory_pages: Option<u64>,
217}
218
219#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
224pub struct RuntimeStateDomainSummary {
225 pub domain: String,
226 pub version: u32,
227 pub storage: String,
228 pub memory_id: Option<u8>,
229 pub status: RuntimeStateDomainStatus,
230}
231
232#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
237pub struct RuntimeAuthStatusSummary {
238 pub auth_features: Vec<RuntimeFeatureStatus>,
239}
240
241#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
246pub struct RuntimeBlobStorageStatusSummary {
247 pub blob_storage_features: Vec<RuntimeFeatureStatus>,
248}
249
250#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
255pub struct RuntimeReceiptCapacityStatus {
256 pub status: RuntimeCheckStatus,
257 pub receipt_records: u64,
258 pub application_receipt_records: u64,
259 pub canic_owned_receipt_records: u64,
260 pub pending_application_receipt_records: u64,
261 pub terminal_application_receipt_records: u64,
262 pub receipt_record_limit: u64,
263 pub remaining_receipt_record_headroom: u64,
264 pub resource_total_records: u64,
265 pub resource_total_record_limit: u64,
266 pub remaining_resource_total_headroom: u64,
267 pub warning_headroom_threshold: u64,
268 pub reserved_terminal_slots: u64,
269 pub reserved_terminal_pages: u64,
270 pub next_terminal_eligibility_at_ns: Option<u64>,
271 pub source: String,
272}
273
274#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
279pub struct RecentFailure {
280 pub occurred_at_ns: u64,
281 pub subsystem: String,
282 pub code: String,
283 pub severity: FailureSeverity,
284 pub summary: String,
285 pub correlation_id: Option<String>,
286 pub redacted: bool,
287}
288
289#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
294pub struct RuntimeVisibilityEntry {
295 pub field: String,
296 pub visibility: RuntimeFieldVisibility,
297}
298
299#[cfg(test)]
300mod tests {
301 use super::*;
302 use candid::{Decode, Encode};
303 use serde::Serialize;
304 use serde::de::DeserializeOwned;
305 use std::fmt::Debug;
306
307 #[test]
308 fn runtime_enums_roundtrip_candid_with_canonical_variant_labels() {
309 assert_enum_candid_contract(HealthStatus::Unknown);
310 assert_enum_candid_contract(ReadinessStatus::NotEvaluated);
311 assert_enum_candid_contract(RuntimeStatus::Failing);
312 assert_enum_candid_contract(TimerRegistrationStatus::Unregistered);
313 assert_enum_candid_contract(TimerProcessCondition::MissingRegistration);
314 assert_enum_candid_contract(TimerSchedulingMode::AfterCompletion);
315 assert_enum_candid_contract(TimerExecutionOutcome::InvariantFailure);
316 assert_enum_candid_contract(FailureSeverity::Critical);
317 assert_enum_candid_contract(RuntimeCheckStatus::NotEvaluated);
318 assert_enum_candid_contract(RuntimeDiagnosticSeverity::Unsupported);
319 assert_enum_candid_contract(RuntimeFieldVisibility::OperatorOnly);
320 assert_enum_candid_contract(RuntimeStateDomainStatus::NotEvaluated);
321 }
322
323 #[test]
324 fn runtime_enums_serialize_canonical_snake_case_labels() {
325 assert_enum_serde_contract(HealthStatus::Healthy, HealthStatus::Healthy.label());
326 assert_enum_serde_contract(HealthStatus::Degraded, HealthStatus::Degraded.label());
327 assert_enum_serde_contract(HealthStatus::Unhealthy, HealthStatus::Unhealthy.label());
328 assert_enum_serde_contract(HealthStatus::Unknown, HealthStatus::Unknown.label());
329
330 assert_enum_serde_contract(ReadinessStatus::Ready, ReadinessStatus::Ready.label());
331 assert_enum_serde_contract(ReadinessStatus::Degraded, ReadinessStatus::Degraded.label());
332 assert_enum_serde_contract(ReadinessStatus::NotReady, ReadinessStatus::NotReady.label());
333 assert_enum_serde_contract(
334 ReadinessStatus::NotEvaluated,
335 ReadinessStatus::NotEvaluated.label(),
336 );
337
338 assert_enum_serde_contract(RuntimeStatus::Ok, RuntimeStatus::Ok.label());
339 assert_enum_serde_contract(RuntimeStatus::Degraded, RuntimeStatus::Degraded.label());
340 assert_enum_serde_contract(RuntimeStatus::Failing, RuntimeStatus::Failing.label());
341 assert_enum_serde_contract(RuntimeStatus::Unknown, RuntimeStatus::Unknown.label());
342
343 assert_enum_serde_contract(
344 TimerRegistrationStatus::Unregistered,
345 TimerRegistrationStatus::Unregistered.label(),
346 );
347 assert_enum_serde_contract(
348 TimerProcessCondition::MissingRegistration,
349 TimerProcessCondition::MissingRegistration.label(),
350 );
351 assert_enum_serde_contract(
352 TimerSchedulingMode::AfterCompletion,
353 TimerSchedulingMode::AfterCompletion.label(),
354 );
355 assert_enum_serde_contract(
356 TimerExecutionOutcome::InvariantFailure,
357 TimerExecutionOutcome::InvariantFailure.label(),
358 );
359
360 assert_enum_serde_contract(FailureSeverity::Info, FailureSeverity::Info.label());
361 assert_enum_serde_contract(FailureSeverity::Warning, FailureSeverity::Warning.label());
362 assert_enum_serde_contract(FailureSeverity::Error, FailureSeverity::Error.label());
363 assert_enum_serde_contract(FailureSeverity::Critical, FailureSeverity::Critical.label());
364
365 assert_enum_serde_contract(RuntimeCheckStatus::Pass, RuntimeCheckStatus::Pass.label());
366 assert_enum_serde_contract(RuntimeCheckStatus::Warn, RuntimeCheckStatus::Warn.label());
367 assert_enum_serde_contract(RuntimeCheckStatus::Fail, RuntimeCheckStatus::Fail.label());
368 assert_enum_serde_contract(
369 RuntimeCheckStatus::NotEvaluated,
370 RuntimeCheckStatus::NotEvaluated.label(),
371 );
372
373 assert_enum_serde_contract(
374 RuntimeDiagnosticSeverity::Info,
375 RuntimeDiagnosticSeverity::Info.label(),
376 );
377 assert_enum_serde_contract(
378 RuntimeDiagnosticSeverity::Warning,
379 RuntimeDiagnosticSeverity::Warning.label(),
380 );
381 assert_enum_serde_contract(
382 RuntimeDiagnosticSeverity::Blocked,
383 RuntimeDiagnosticSeverity::Blocked.label(),
384 );
385 assert_enum_serde_contract(
386 RuntimeDiagnosticSeverity::Unsupported,
387 RuntimeDiagnosticSeverity::Unsupported.label(),
388 );
389
390 assert_enum_serde_contract(
391 RuntimeFieldVisibility::PublicSafe,
392 RuntimeFieldVisibility::PublicSafe.label(),
393 );
394 assert_enum_serde_contract(
395 RuntimeFieldVisibility::OperatorOnly,
396 RuntimeFieldVisibility::OperatorOnly.label(),
397 );
398 assert_enum_serde_contract(
399 RuntimeFieldVisibility::ControllerOnly,
400 RuntimeFieldVisibility::ControllerOnly.label(),
401 );
402 assert_enum_serde_contract(
403 RuntimeFieldVisibility::FeatureGated,
404 RuntimeFieldVisibility::FeatureGated.label(),
405 );
406 assert_enum_serde_contract(
407 RuntimeFieldVisibility::Disabled,
408 RuntimeFieldVisibility::Disabled.label(),
409 );
410
411 assert_enum_serde_contract(
412 RuntimeStateDomainStatus::Ok,
413 RuntimeStateDomainStatus::Ok.label(),
414 );
415 assert_enum_serde_contract(
416 RuntimeStateDomainStatus::Warning,
417 RuntimeStateDomainStatus::Warning.label(),
418 );
419 assert_enum_serde_contract(
420 RuntimeStateDomainStatus::Failing,
421 RuntimeStateDomainStatus::Failing.label(),
422 );
423 assert_enum_serde_contract(
424 RuntimeStateDomainStatus::NotEvaluated,
425 RuntimeStateDomainStatus::NotEvaluated.label(),
426 );
427 }
428
429 fn assert_enum_candid_contract<T>(value: T)
430 where
431 T: CandidType + Clone + Debug + DeserializeOwned + Eq,
432 {
433 let bytes = Encode!(&value).expect("encode runtime enum");
434 let decoded = Decode!(&bytes, T).expect("decode runtime enum");
435
436 assert_eq!(decoded, value);
437 }
438
439 fn assert_enum_serde_contract<T>(value: T, label: &str)
440 where
441 T: Clone + Debug + DeserializeOwned + Eq + Serialize,
442 {
443 let encoded = crate::cdk::serialize::serialize(&value).expect("encode runtime enum label");
444 let serialized_label: String =
445 crate::cdk::serialize::deserialize(&encoded).expect("decode runtime enum label");
446 assert_eq!(serialized_label, label);
447
448 let label_bytes =
449 crate::cdk::serialize::serialize(&label).expect("encode canonical runtime enum label");
450 let decoded: T = crate::cdk::serialize::deserialize(&label_bytes)
451 .expect("decode canonical runtime enum label");
452 assert_eq!(decoded, value);
453 }
454}