1616//! This crate provides common service discovery, health check and load balancing
1717//! algorithms for proxies to use.
1818
19+ // https://github.com/mcarton/rust-derivative/issues/112
20+ // False positive for macro generated code
21+ #![ allow( clippy:: non_canonical_partial_ord_impl) ]
22+
1923use arc_swap:: ArcSwap ;
24+ use derivative:: Derivative ;
2025use futures:: FutureExt ;
26+ pub use http:: Extensions ;
2127use pingora_core:: protocols:: l4:: socket:: SocketAddr ;
2228use pingora_error:: { ErrorType , OrErr , Result } ;
2329use std:: collections:: hash_map:: DefaultHasher ;
@@ -45,13 +51,26 @@ pub mod prelude {
4551}
4652
4753/// [Backend] represents a server to proxy or connect to.
48- #[ derive( Clone , Hash , PartialEq , Eq , PartialOrd , Ord , Debug ) ]
54+ #[ derive( Derivative ) ]
55+ #[ derivative( Clone , Hash , PartialEq , PartialOrd , Eq , Ord , Debug ) ]
4956pub struct Backend {
5057 /// The address to the backend server.
5158 pub addr : SocketAddr ,
5259 /// The relative weight of the server. Load balancing algorithms will
5360 /// proportionally distributed traffic according to this value.
5461 pub weight : usize ,
62+
63+ /// The extension field to put arbitrary data to annotate the Backend.
64+ /// The data added here is opaque to this crate hence the data is ignored by
65+ /// functionalities of this crate. For example, two backends with the same
66+ /// [SocketAddr] and the same weight but different `ext` data are considered
67+ /// identical.
68+ /// See [Extensions] for how to add and read the data.
69+ #[ derivative( PartialEq = "ignore" ) ]
70+ #[ derivative( PartialOrd = "ignore" ) ]
71+ #[ derivative( Hash = "ignore" ) ]
72+ #[ derivative( Ord = "ignore" ) ]
73+ pub ext : Extensions ,
5574}
5675
5776impl Backend {
@@ -64,6 +83,7 @@ impl Backend {
6483 Ok ( Backend {
6584 addr : SocketAddr :: Inet ( addr) ,
6685 weight : 1 ,
86+ ext : Extensions :: new ( ) ,
6787 } )
6888 // TODO: UDS
6989 }
@@ -449,6 +469,31 @@ mod test {
449469 assert ! ( backends. ready( & good2) ) ;
450470 assert ! ( !backends. ready( & bad) ) ;
451471 }
472+ #[ tokio:: test]
473+ async fn test_backends_with_ext ( ) {
474+ let discovery = discovery:: Static :: default ( ) ;
475+ let mut b1 = Backend :: new ( "1.1.1.1:80" ) . unwrap ( ) ;
476+ b1. ext . insert ( true ) ;
477+ let mut b2 = Backend :: new ( "1.0.0.1:80" ) . unwrap ( ) ;
478+ b2. ext . insert ( 1u8 ) ;
479+ discovery. add ( b1. clone ( ) ) ;
480+ discovery. add ( b2. clone ( ) ) ;
481+
482+ let backends = Backends :: new ( Box :: new ( discovery) ) ;
483+
484+ // fill in the backends
485+ backends. update ( ) . await . unwrap ( ) ;
486+
487+ let backend = backends. get_backend ( ) ;
488+ assert ! ( backend. contains( & b1) ) ;
489+ assert ! ( backend. contains( & b2) ) ;
490+
491+ let b2 = backend. first ( ) . unwrap ( ) ;
492+ assert_eq ! ( b2. ext. get:: <u8 >( ) , Some ( & 1 ) ) ;
493+
494+ let b1 = backend. last ( ) . unwrap ( ) ;
495+ assert_eq ! ( b1. ext. get:: <bool >( ) , Some ( & true ) ) ;
496+ }
452497
453498 #[ tokio:: test]
454499 async fn test_discovery_readiness ( ) {
0 commit comments