Skip to main content

Vine/Client/
ConnectToSideCar.rs

1//! Establish a gRPC connection to a Cocoon sidecar with exponential
2//! back-off retry. On success initialises the per-connection metadata
3//! tracked by `Shared::CONNECTION_METADATA`.
4
5use std::time::{Duration, Instant};
6
7use crate::{
8	Client::{
9		Shared::{
10			CONNECTION_METADATA,
11			ConnectionMetadata,
12			FireConnectionNotify,
13			MAX_RETRY_ATTEMPTS,
14			RETRY_BASE_DELAY_MS,
15		},
16		TryConnectSingle,
17	},
18	Error::VineError,
19	dev_log,
20};
21
22pub async fn Fn(SideCarIdentifier:String, Address:String) -> Result<(), VineError> {
23	dev_log!(
24		"grpc",
25		"[VineClient] Connecting to sidecar '{}' at '{}'...",
26		SideCarIdentifier,
27		Address
28	);
29
30	let Endpoint = format!("http://{}", Address);
31
32	if Endpoint.len() > 256 {
33		return Err(VineError::RPCError(
34			"Invalid endpoint address: exceeds maximum length".to_string(),
35		));
36	}
37
38	let mut LastError = None;
39
40	for Attempt in 1..=MAX_RETRY_ATTEMPTS {
41		let Result = TryConnectSingle::Fn(&SideCarIdentifier, &Endpoint).await;
42
43		if Result.is_ok() {
44			CONNECTION_METADATA.lock().insert(
45				SideCarIdentifier.clone(),
46				ConnectionMetadata { LastActivity:Instant::now(), FailureCount:0, IsHealthy:true },
47			);
48
49			dev_log!("grpc", "[VineClient] Successfully connected to sidecar '{}'", SideCarIdentifier);
50
51			// Unblock any `WaitForClientConnection` callers immediately.
52			FireConnectionNotify(&SideCarIdentifier);
53
54			return Result;
55		}
56
57		LastError = Some(Result.unwrap_err());
58
59		if Attempt < MAX_RETRY_ATTEMPTS {
60			let DelayMilliseconds = RETRY_BASE_DELAY_MS * 2_u64.pow(Attempt as u32);
61
62			tokio::time::sleep(Duration::from_millis(DelayMilliseconds)).await;
63		}
64	}
65
66	Err(LastError.unwrap_or_else(|| VineError::RPCError("Connection failed".to_string())))
67}