grafos_registry/registration.rs
1//! Service registration and health status types.
2
3extern crate alloc;
4use alloc::string::String;
5use alloc::vec::Vec;
6
7use serde::{Deserialize, Serialize};
8
9use crate::endpoint::ServiceEndpoint;
10
11/// Health status of a service instance.
12#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
13pub enum HealthStatus {
14 /// Instance is operating normally.
15 Healthy,
16 /// Instance is functional but impaired.
17 Degraded {
18 /// Human-readable reason for degradation.
19 reason: String,
20 },
21 /// Instance is shutting down and should not receive new work.
22 Draining,
23}
24
25/// A tag key-value pair attached to a service registration.
26#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
27pub struct Tag {
28 /// Tag key.
29 pub key: String,
30 /// Tag value.
31 pub value: String,
32}
33
34/// A single service registration in the registry.
35///
36/// Each registration identifies a unique instance of a named service with a
37/// version string, instance ID, endpoints, tags, health status, and a lease
38/// expiry timestamp (set by the registry on insertion).
39#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
40pub struct ServiceRegistration {
41 /// Service name (e.g. `"api-gateway"`).
42 pub name: String,
43 /// Semantic version string (e.g. `"2.1.0"`).
44 pub version: String,
45 /// Unique instance identifier.
46 pub instance_id: u128,
47 /// Reachable endpoints for this instance.
48 pub endpoints: Vec<ServiceEndpoint>,
49 /// Metadata tags for filtering.
50 pub tags: Vec<Tag>,
51 /// Current health status.
52 pub health: HealthStatus,
53 /// Unix timestamp (seconds) at which this registration expires.
54 /// Set by the registry on insertion; 0 means "not yet registered".
55 pub lease_expires_at: u64,
56}
57
58impl ServiceRegistration {
59 /// Create a new registration with the given name, version, and instance ID.
60 ///
61 /// Defaults to [`HealthStatus::Healthy`], no endpoints, no tags, and
62 /// `lease_expires_at = 0`.
63 pub fn new(name: &str, version: &str, instance_id: u128) -> Self {
64 ServiceRegistration {
65 name: String::from(name),
66 version: String::from(version),
67 instance_id,
68 endpoints: Vec::new(),
69 tags: Vec::new(),
70 health: HealthStatus::Healthy,
71 lease_expires_at: 0,
72 }
73 }
74
75 /// Add an endpoint to this registration (builder pattern).
76 pub fn with_endpoint(mut self, endpoint: ServiceEndpoint) -> Self {
77 self.endpoints.push(endpoint);
78 self
79 }
80
81 /// Add a tag to this registration (builder pattern).
82 pub fn with_tag(mut self, key: &str, value: &str) -> Self {
83 self.tags.push(Tag {
84 key: String::from(key),
85 value: String::from(value),
86 });
87 self
88 }
89
90 /// Check whether all required tags are present (AND semantics).
91 pub fn has_tags(&self, required: &[(String, String)]) -> bool {
92 required
93 .iter()
94 .all(|(rk, rv)| self.tags.iter().any(|t| t.key == *rk && t.value == *rv))
95 }
96
97 /// Check whether the version string starts with the given prefix.
98 pub fn version_matches_prefix(&self, prefix: &str) -> bool {
99 self.version.starts_with(prefix)
100 }
101}