2929//!
3030//! TODO: Top-level Overview of Endpoints/Functions
3131
32+ use std:: fmt;
33+
3234use crate :: {
3335 config:: HealthStatus ,
3436 discovery:: Lease ,
@@ -70,7 +72,7 @@ pub mod service;
7072
7173pub use client:: { Client , InstanceSource } ;
7274
73- /// The root etcd path where each instance registers itself in etcd .
75+ /// The root key-value path where each instance registers itself in.
7476/// An instance is namespace+component+endpoint+lease_id and must be unique.
7577pub const INSTANCE_ROOT_PATH : & str = "v1/instances" ;
7678
@@ -91,7 +93,7 @@ pub struct Registry {
9193 inner : Arc < tokio:: sync:: Mutex < RegistryInner > > ,
9294}
9395
94- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
96+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , Eq ) ]
9597pub struct Instance {
9698 pub component : String ,
9799 pub endpoint : String ,
@@ -113,6 +115,30 @@ impl Instance {
113115 }
114116}
115117
118+ impl fmt:: Display for Instance {
119+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
120+ write ! (
121+ f,
122+ "{}/{}/{}/{}" ,
123+ self . namespace, self . component, self . endpoint, self . instance_id
124+ )
125+ }
126+ }
127+
128+ /// Sort by string name
129+ impl std:: cmp:: Ord for Instance {
130+ fn cmp ( & self , other : & Self ) -> std:: cmp:: Ordering {
131+ self . to_string ( ) . cmp ( & other. to_string ( ) )
132+ }
133+ }
134+
135+ impl PartialOrd for Instance {
136+ fn partial_cmp ( & self , other : & Self ) -> Option < std:: cmp:: Ordering > {
137+ // Since Ord is fully implemented, the comparison is always total.
138+ Some ( self . cmp ( other) )
139+ }
140+ }
141+
116142/// A [Component] a discoverable entity in the distributed runtime.
117143/// You can host [Endpoint] on a [Component] by first creating
118144/// a [Service] then adding one or more [Endpoint] to the [Service].
@@ -197,8 +223,8 @@ impl MetricsRegistry for Component {
197223}
198224
199225impl Component {
200- /// The component part of an instance path in etcd .
201- pub fn etcd_root ( & self ) -> String {
226+ /// The component part of an instance path in key-value store .
227+ pub fn instance_root ( & self ) -> String {
202228 let ns = self . namespace . name ( ) ;
203229 let cp = & self . name ;
204230 format ! ( "{INSTANCE_ROOT_PATH}/{ns}/{cp}" )
@@ -240,27 +266,23 @@ impl Component {
240266 }
241267
242268 pub async fn list_instances ( & self ) -> anyhow:: Result < Vec < Instance > > {
243- let Some ( etcd_client) = self . drt . etcd_client ( ) else {
269+ let client = self . drt . store ( ) ;
270+ let Some ( bucket) = client. get_bucket ( & self . instance_root ( ) ) . await ? else {
244271 return Ok ( vec ! [ ] ) ;
245272 } ;
246- let mut out = vec ! [ ] ;
247- // The extra slash is important to only list exact component matches, not substrings.
248- for kv in etcd_client
249- . kv_get_prefix ( format ! ( "{}/" , self . etcd_root( ) ) )
250- . await ?
251- {
252- let val = match serde_json:: from_slice :: < Instance > ( kv. value ( ) ) {
273+ let entries = bucket. entries ( ) . await ?;
274+ let mut instances = Vec :: with_capacity ( entries. len ( ) ) ;
275+ for ( name, bytes) in entries. into_iter ( ) {
276+ let val = match serde_json:: from_slice :: < Instance > ( & bytes) {
253277 Ok ( val) => val,
254278 Err ( err) => {
255- anyhow:: bail!(
256- "Error converting etcd response to Instance: {err}. {}" ,
257- kv. value_str( ) ?
258- ) ;
279+ anyhow:: bail!( "Error converting storage response to Instance: {err}. {name}" , ) ;
259280 }
260281 } ;
261- out . push ( val) ;
282+ instances . push ( val) ;
262283 }
263- Ok ( out)
284+ instances. sort ( ) ;
285+ Ok ( instances)
264286 }
265287
266288 /// Scrape ServiceSet, which contains NATS stats as well as user defined stats
@@ -445,7 +467,7 @@ impl Endpoint {
445467
446468 /// The endpoint part of an instance path in etcd
447469 pub fn etcd_root ( & self ) -> String {
448- let component_path = self . component . etcd_root ( ) ;
470+ let component_path = self . component . instance_root ( ) ;
449471 let endpoint_name = & self . name ;
450472 format ! ( "{component_path}/{endpoint_name}" )
451473 }
0 commit comments