Share cached exec-server environment info with Arc (#49798)

## What changed

Return `Arc<EnvironmentInfo>` from `ExecServerClient::environment_info()` so repeated reads and cloned clients share cached metadata without cloning its contents. Wrap metadata from initialization and lazy RPC fetches in `Arc`, while preserving the owned return value in `LazyRemoteExecServerClient`.

## Testing

Extend the cache test to assert pointer identity across cloned clients for both initialization-provided metadata and lazy fetching after connecting to a legacy server.

GitOrigin-RevId: 3f56f4d51a4aebc0c4821c0b128a70efb23933d4
This commit is contained in:
Adam Perry @ OpenAI
2026-10-01 01:22:28 +00:00
committed by copyberry
parent 5ca55db09c
commit c538fbabe5
2 changed files with 12 additions and 9 deletions
+1 -1
View File
@@ -267,7 +267,7 @@ metrics_exporter = {{ otlp-http = {{ endpoint = "{collector_url}/v1/metrics", pr
prepend_path_dirs: environment_info.prepend_path_dirs.clone(),
..EnvironmentInfo::local()
};
assert_eq!(environment_info, expected_info);
assert_eq!(environment_info.as_ref(), &expected_info);
std::fs::remove_file(&manifest)?;
assert_eq!(client.force_environment_info().await?, expected_info);
+11 -8
View File
@@ -290,7 +290,7 @@ struct Inner {
session_id: OnceLock<String>,
retired: CancellationToken,
/// Caches metadata from initialization or the first successful info request for this client's lifetime.
environment_info: OnceCell<EnvironmentInfo>,
environment_info: OnceCell<Arc<EnvironmentInfo>>,
reconnect_strategy: Option<ExecServerReconnectStrategy>,
}
@@ -652,7 +652,7 @@ impl HttpClient for LazyRemoteExecServerClient {
impl LazyRemoteExecServerClient {
pub(crate) async fn environment_info(&self) -> Result<EnvironmentInfo, ExecServerError> {
self.get().await?.environment_info().await
Ok(self.get().await?.environment_info().await?.as_ref().clone())
}
}
@@ -827,11 +827,11 @@ impl ExecServerClient {
self.call(EXEC_METHOD, &params).await
}
/// Returns cached executor metadata, fetching it lazily if initialization omitted it.
pub async fn environment_info(&self) -> Result<EnvironmentInfo, ExecServerError> {
/// Returns shared cached executor metadata, fetching it lazily if initialization omitted it.
pub async fn environment_info(&self) -> Result<Arc<EnvironmentInfo>, ExecServerError> {
self.inner
.environment_info
.get_or_try_init(|| self.force_environment_info())
.get_or_try_init(|| async { self.force_environment_info().await.map(Arc::new) })
.await
.cloned()
}
@@ -1292,7 +1292,7 @@ impl ExecServerClient {
.await?;
if let Some(info) = initialize_response.environment_info {
assert!(
client.inner.environment_info.set(info).is_ok(),
client.inner.environment_info.set(Arc::new(info)).is_ok(),
"new client metadata cache must be empty"
);
}
@@ -2668,10 +2668,13 @@ mod tests {
})
.await?;
assert_eq!(client.environment_info().await?, expected_info);
let info = client.environment_info().await?;
assert_eq!(info.as_ref(), &expected_info);
server.await?;
// The server is gone, so a cloned client must use the shared cache.
assert_eq!(client.clone().environment_info().await?, expected_info);
let cached_info = client.clone().environment_info().await?;
assert_eq!(cached_info.as_ref(), &expected_info);
assert!(Arc::ptr_eq(&info, &cached_info));
Ok(())
}