Skip to main content

canic_core/dto/
runtime.rs

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//
13// CanicHealthStatus
14//
15
16#[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//
25// CanicReadinessStatus
26//
27
28#[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//
40// CanicRuntimeStatus
41//
42
43#[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<CanicTimerStatus>,
55    pub state: Option<RuntimeStateSummary>,
56    pub auth: Option<RuntimeAuthStatusSummary>,
57    pub blob_storage: Option<RuntimeBlobStorageStatusSummary>,
58    pub receipt_capacity: Option<RuntimeReceiptCapacityStatus>,
59    pub recent_failures: Vec<RecentFailure>,
60    pub visibility: Vec<RuntimeVisibilityEntry>,
61    pub readiness: CanicReadinessStatus,
62    pub status: RuntimeStatus,
63}
64
65//
66// RuntimeBuildInfo
67//
68
69#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
70pub struct RuntimeBuildInfo {
71    pub package_name: String,
72    pub package_version: String,
73    pub canic_version: String,
74    pub canister_version: u64,
75}
76
77//
78// RuntimeCheck
79//
80
81#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
82pub struct RuntimeCheck {
83    pub category: String,
84    pub code: String,
85    pub status: RuntimeCheckStatus,
86    pub subject: String,
87    pub detail: String,
88    pub next: Option<String>,
89    pub source: String,
90}
91
92//
93// RuntimeDiagnostic
94//
95
96#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
97pub struct RuntimeDiagnostic {
98    pub category: String,
99    pub code: String,
100    pub severity: RuntimeDiagnosticSeverity,
101    pub subject: String,
102    pub detail: String,
103    pub next: Option<String>,
104    pub source: String,
105}
106
107//
108// RuntimeFeatureStatus
109//
110
111#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
112pub struct RuntimeFeatureStatus {
113    pub name: String,
114    pub enabled: bool,
115    pub visibility: RuntimeFieldVisibility,
116    pub source: String,
117}
118
119//
120// RuntimeTopologyStatus
121//
122
123#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
124pub struct RuntimeTopologyStatus {
125    pub root: Option<Principal>,
126    pub parent: Option<Principal>,
127    pub subnet: Option<Principal>,
128    pub source: String,
129}
130
131//
132// CanicTimerStatus
133//
134
135#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
136pub struct CanicTimerStatus {
137    pub name: String,
138    pub subsystem: String,
139    pub scheduling_mode: TimerSchedulingMode,
140    pub registration: TimerRegistrationStatus,
141    pub condition: TimerProcessCondition,
142    pub enabled: bool,
143    pub generation: u64,
144    pub next_due_at_ns: Option<u64>,
145    pub last_outcome: Option<TimerExecutionOutcome>,
146    pub last_work_count: u64,
147    pub last_success_at_ns: Option<u64>,
148    pub last_failure_at_ns: Option<u64>,
149    pub consecutive_expected_failures: u64,
150    pub schedules_since_runtime_start: u64,
151    pub executions_since_runtime_start: u64,
152    pub successes_since_runtime_start: u64,
153    pub expected_failures_since_runtime_start: u64,
154    pub invariant_failures_since_runtime_start: u64,
155    pub stale_callbacks_since_runtime_start: u64,
156}
157
158//
159// RuntimeStateSummary
160//
161
162#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
163pub struct RuntimeStateSummary {
164    pub manifest_schema_version: u32,
165    pub domains: Vec<RuntimeStateDomainSummary>,
166    pub total_stable_memory_pages: Option<u64>,
167}
168
169//
170// RuntimeStateDomainSummary
171//
172
173#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
174pub struct RuntimeStateDomainSummary {
175    pub domain: String,
176    pub version: u32,
177    pub storage: String,
178    pub memory_id: Option<u8>,
179    pub status: RuntimeStateDomainStatus,
180}
181
182//
183// RuntimeAuthStatusSummary
184//
185
186#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
187pub struct RuntimeAuthStatusSummary {
188    pub auth_features: Vec<RuntimeFeatureStatus>,
189}
190
191//
192// RuntimeBlobStorageStatusSummary
193//
194
195#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
196pub struct RuntimeBlobStorageStatusSummary {
197    pub blob_storage_features: Vec<RuntimeFeatureStatus>,
198}
199
200//
201// RuntimeReceiptCapacityStatus
202//
203
204#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
205pub struct RuntimeReceiptCapacityStatus {
206    pub status: RuntimeCheckStatus,
207    pub receipt_records: u64,
208    pub application_receipt_records: u64,
209    pub canic_owned_receipt_records: u64,
210    pub pending_application_receipt_records: u64,
211    pub terminal_application_receipt_records: u64,
212    pub receipt_record_limit: u64,
213    pub remaining_receipt_record_headroom: u64,
214    pub resource_total_records: u64,
215    pub resource_total_record_limit: u64,
216    pub remaining_resource_total_headroom: u64,
217    pub warning_headroom_threshold: u64,
218    pub reserved_terminal_slots: u64,
219    pub reserved_terminal_pages: u64,
220    pub next_terminal_eligibility_at_ns: Option<u64>,
221    pub source: String,
222}
223
224//
225// RecentFailure
226//
227
228#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
229pub struct RecentFailure {
230    pub occurred_at_ns: u64,
231    pub subsystem: String,
232    pub code: String,
233    pub severity: FailureSeverity,
234    pub summary: String,
235    pub correlation_id: Option<String>,
236    pub redacted: bool,
237}
238
239//
240// RuntimeVisibilityEntry
241//
242
243#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
244pub struct RuntimeVisibilityEntry {
245    pub field: String,
246    pub visibility: RuntimeFieldVisibility,
247}
248
249#[cfg(test)]
250mod tests {
251    use super::*;
252    use candid::{Decode, Encode};
253    use serde::Serialize;
254    use serde::de::DeserializeOwned;
255    use std::fmt::Debug;
256
257    #[test]
258    fn runtime_enums_roundtrip_candid_with_canonical_variant_labels() {
259        assert_enum_candid_contract(HealthStatus::Unknown);
260        assert_enum_candid_contract(ReadinessStatus::NotEvaluated);
261        assert_enum_candid_contract(RuntimeStatus::Failing);
262        assert_enum_candid_contract(TimerRegistrationStatus::Unregistered);
263        assert_enum_candid_contract(TimerProcessCondition::MissingRegistration);
264        assert_enum_candid_contract(TimerSchedulingMode::AfterCompletion);
265        assert_enum_candid_contract(TimerExecutionOutcome::InvariantFailure);
266        assert_enum_candid_contract(FailureSeverity::Critical);
267        assert_enum_candid_contract(RuntimeCheckStatus::NotEvaluated);
268        assert_enum_candid_contract(RuntimeDiagnosticSeverity::Unsupported);
269        assert_enum_candid_contract(RuntimeFieldVisibility::OperatorOnly);
270        assert_enum_candid_contract(RuntimeStateDomainStatus::NotEvaluated);
271    }
272
273    #[test]
274    fn runtime_enums_serialize_canonical_snake_case_labels() {
275        assert_enum_serde_contract(HealthStatus::Healthy, HealthStatus::Healthy.label());
276        assert_enum_serde_contract(HealthStatus::Degraded, HealthStatus::Degraded.label());
277        assert_enum_serde_contract(HealthStatus::Unhealthy, HealthStatus::Unhealthy.label());
278        assert_enum_serde_contract(HealthStatus::Unknown, HealthStatus::Unknown.label());
279
280        assert_enum_serde_contract(ReadinessStatus::Ready, ReadinessStatus::Ready.label());
281        assert_enum_serde_contract(ReadinessStatus::Degraded, ReadinessStatus::Degraded.label());
282        assert_enum_serde_contract(ReadinessStatus::NotReady, ReadinessStatus::NotReady.label());
283        assert_enum_serde_contract(
284            ReadinessStatus::NotEvaluated,
285            ReadinessStatus::NotEvaluated.label(),
286        );
287
288        assert_enum_serde_contract(RuntimeStatus::Ok, RuntimeStatus::Ok.label());
289        assert_enum_serde_contract(RuntimeStatus::Degraded, RuntimeStatus::Degraded.label());
290        assert_enum_serde_contract(RuntimeStatus::Failing, RuntimeStatus::Failing.label());
291        assert_enum_serde_contract(RuntimeStatus::Unknown, RuntimeStatus::Unknown.label());
292
293        assert_enum_serde_contract(
294            TimerRegistrationStatus::Unregistered,
295            TimerRegistrationStatus::Unregistered.label(),
296        );
297        assert_enum_serde_contract(
298            TimerProcessCondition::MissingRegistration,
299            TimerProcessCondition::MissingRegistration.label(),
300        );
301        assert_enum_serde_contract(
302            TimerSchedulingMode::AfterCompletion,
303            TimerSchedulingMode::AfterCompletion.label(),
304        );
305        assert_enum_serde_contract(
306            TimerExecutionOutcome::InvariantFailure,
307            TimerExecutionOutcome::InvariantFailure.label(),
308        );
309
310        assert_enum_serde_contract(FailureSeverity::Info, FailureSeverity::Info.label());
311        assert_enum_serde_contract(FailureSeverity::Warning, FailureSeverity::Warning.label());
312        assert_enum_serde_contract(FailureSeverity::Error, FailureSeverity::Error.label());
313        assert_enum_serde_contract(FailureSeverity::Critical, FailureSeverity::Critical.label());
314
315        assert_enum_serde_contract(RuntimeCheckStatus::Pass, RuntimeCheckStatus::Pass.label());
316        assert_enum_serde_contract(RuntimeCheckStatus::Warn, RuntimeCheckStatus::Warn.label());
317        assert_enum_serde_contract(RuntimeCheckStatus::Fail, RuntimeCheckStatus::Fail.label());
318        assert_enum_serde_contract(
319            RuntimeCheckStatus::NotEvaluated,
320            RuntimeCheckStatus::NotEvaluated.label(),
321        );
322
323        assert_enum_serde_contract(
324            RuntimeDiagnosticSeverity::Info,
325            RuntimeDiagnosticSeverity::Info.label(),
326        );
327        assert_enum_serde_contract(
328            RuntimeDiagnosticSeverity::Warning,
329            RuntimeDiagnosticSeverity::Warning.label(),
330        );
331        assert_enum_serde_contract(
332            RuntimeDiagnosticSeverity::Blocked,
333            RuntimeDiagnosticSeverity::Blocked.label(),
334        );
335        assert_enum_serde_contract(
336            RuntimeDiagnosticSeverity::Unsupported,
337            RuntimeDiagnosticSeverity::Unsupported.label(),
338        );
339
340        assert_enum_serde_contract(
341            RuntimeFieldVisibility::PublicSafe,
342            RuntimeFieldVisibility::PublicSafe.label(),
343        );
344        assert_enum_serde_contract(
345            RuntimeFieldVisibility::OperatorOnly,
346            RuntimeFieldVisibility::OperatorOnly.label(),
347        );
348        assert_enum_serde_contract(
349            RuntimeFieldVisibility::ControllerOnly,
350            RuntimeFieldVisibility::ControllerOnly.label(),
351        );
352        assert_enum_serde_contract(
353            RuntimeFieldVisibility::FeatureGated,
354            RuntimeFieldVisibility::FeatureGated.label(),
355        );
356        assert_enum_serde_contract(
357            RuntimeFieldVisibility::Disabled,
358            RuntimeFieldVisibility::Disabled.label(),
359        );
360
361        assert_enum_serde_contract(
362            RuntimeStateDomainStatus::Ok,
363            RuntimeStateDomainStatus::Ok.label(),
364        );
365        assert_enum_serde_contract(
366            RuntimeStateDomainStatus::Warning,
367            RuntimeStateDomainStatus::Warning.label(),
368        );
369        assert_enum_serde_contract(
370            RuntimeStateDomainStatus::Failing,
371            RuntimeStateDomainStatus::Failing.label(),
372        );
373        assert_enum_serde_contract(
374            RuntimeStateDomainStatus::NotEvaluated,
375            RuntimeStateDomainStatus::NotEvaluated.label(),
376        );
377    }
378
379    fn assert_enum_candid_contract<T>(value: T)
380    where
381        T: CandidType + Clone + Debug + DeserializeOwned + Eq,
382    {
383        let bytes = Encode!(&value).expect("encode runtime enum");
384        let decoded = Decode!(&bytes, T).expect("decode runtime enum");
385
386        assert_eq!(decoded, value);
387    }
388
389    fn assert_enum_serde_contract<T>(value: T, label: &str)
390    where
391        T: Clone + Debug + DeserializeOwned + Eq + Serialize,
392    {
393        let encoded = crate::cdk::serialize::serialize(&value).expect("encode runtime enum label");
394        let serialized_label: String =
395            crate::cdk::serialize::deserialize(&encoded).expect("decode runtime enum label");
396        assert_eq!(serialized_label, label);
397
398        let label_bytes =
399            crate::cdk::serialize::serialize(&label).expect("encode canonical runtime enum label");
400        let decoded: T = crate::cdk::serialize::deserialize(&label_bytes)
401            .expect("decode canonical runtime enum label");
402        assert_eq!(decoded, value);
403    }
404}