Skip to main content

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