mirror of
https://github.com/openai/codex.git
synced 2026-10-29 19:08:43 +00:00
Add optional process metrics sampling for code-mode hosts (#57841)
## What changed - Add `GetProcessMetrics` and provider sampling APIs for process ID, start time, cumulative CPU time, and resident memory, exposed through `ThreadManager` without creating a thread or session. - Distinguish unsupported collection, a locally absent host, and sampling failures. Process-owned providers never start or replace a host when sampling. - Bound gRPC sampling to one second without retries or explicit connection resets. Run optional collectors on a detached worker with at most one collection in flight, so stalled collection cannot block the HTTP/2 driver or runtime shutdown. ## Testing Add coverage for snapshots, collector errors and panics, deadlines, overload, and shutdown with a stuck collector. Extend lifecycle tests to check that sampling preserves session state and keepalive behavior without starting or restarting local hosts. GitOrigin-RevId: eeafe275891d0464636f28a29345a87aed1a12dc
This commit is contained in:
@@ -46,6 +46,7 @@ mod conversion;
|
||||
mod deadline;
|
||||
mod generation;
|
||||
mod operations;
|
||||
mod process_metrics;
|
||||
mod reconnect;
|
||||
mod state;
|
||||
mod transport;
|
||||
@@ -65,6 +66,11 @@ fn inject_span_traceparent<T>(request: &mut tonic::Request<T>, span: &tracing::S
|
||||
}
|
||||
|
||||
/// Creates code-mode sessions over an HTTP/2 gRPC connection.
|
||||
///
|
||||
/// Metrics requests do not open sessions, retry RPCs, or explicitly reset the
|
||||
/// connection. URL providers may initialize their client or establish a network
|
||||
/// connection; caller-supplied channels and transports retain their reconnect
|
||||
/// policy. Preventing child creation requires a process-owned transport.
|
||||
#[derive(Clone)]
|
||||
pub struct GrpcCodeModeSessionProvider {
|
||||
transport: Arc<SharedTransport>,
|
||||
@@ -94,7 +100,8 @@ impl GrpcCodeModeSessionProvider {
|
||||
Self::from_transport(SharedTransport::with_channel(channel))
|
||||
}
|
||||
|
||||
/// Uses a caller-owned transport to control connection establishment and recovery.
|
||||
/// Uses a caller-owned transport, which can prevent observation RPCs from
|
||||
/// starting or replacing process-owned connections.
|
||||
pub fn with_transport<T>(transport: T) -> Self
|
||||
where
|
||||
T: tower::Service<
|
||||
@@ -238,6 +245,13 @@ impl GrpcCodeModeSessionProvider {
|
||||
}
|
||||
|
||||
impl CodeModeSessionProvider for GrpcCodeModeSessionProvider {
|
||||
fn sample_process_metrics(
|
||||
&self,
|
||||
) -> CodeModeSessionResultFuture<'_, codex_code_mode_protocol::CodeModeProcessMetricsSample>
|
||||
{
|
||||
Box::pin(process_metrics::sample(self))
|
||||
}
|
||||
|
||||
fn create_session(&self) -> CodeModeSessionProviderFuture<'_> {
|
||||
self.create_session_with_limits(CodeModeSessionCellExecutionLimits::default())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
//! A bounded, non-retrying host observation. No session binding or recovery is
|
||||
//! involved: a failed RPC never explicitly retires the execution connection.
|
||||
//! Connection establishment and reconnection remain the transport's policy.
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use codex_code_mode_protocol::CodeModeProcessMetrics;
|
||||
use codex_code_mode_protocol::CodeModeProcessMetricsSample;
|
||||
use codex_code_mode_protocol::grpc;
|
||||
use tonic::Code;
|
||||
|
||||
use super::GrpcCodeModeSessionProvider;
|
||||
|
||||
pub(super) async fn sample(
|
||||
provider: &GrpcCodeModeSessionProvider,
|
||||
) -> Result<CodeModeProcessMetricsSample, String> {
|
||||
let deadline = Duration::from_secs(/*secs*/ 1);
|
||||
tokio::time::timeout(deadline, async {
|
||||
let mut client = provider.transport.client().await?;
|
||||
let mut request = tonic::Request::new(grpc::GetProcessMetricsRequest {});
|
||||
request.set_timeout(deadline);
|
||||
match client.get_process_metrics(request).await {
|
||||
Ok(response) => {
|
||||
let snapshot = response.into_inner();
|
||||
if snapshot.process_id == 0
|
||||
|| !snapshot.process_start_time_seconds.is_finite()
|
||||
|| snapshot.process_start_time_seconds <= 0.0
|
||||
|| !snapshot.cpu_seconds_total.is_finite()
|
||||
|| snapshot.cpu_seconds_total < 0.0
|
||||
{
|
||||
return Err("invalid code-mode process metrics snapshot".to_string());
|
||||
}
|
||||
Ok(CodeModeProcessMetricsSample::Snapshot(
|
||||
CodeModeProcessMetrics {
|
||||
process_id: snapshot.process_id,
|
||||
process_start_time_seconds: snapshot.process_start_time_seconds,
|
||||
cpu_seconds_total: snapshot.cpu_seconds_total,
|
||||
resident_memory_bytes: snapshot.resident_memory_bytes,
|
||||
},
|
||||
))
|
||||
}
|
||||
Err(status) if status.code() == Code::Unimplemented => {
|
||||
Ok(CodeModeProcessMetricsSample::Unsupported)
|
||||
}
|
||||
Err(status) => Err(format!("code-mode process metrics failed: {status}")),
|
||||
}
|
||||
})
|
||||
.await
|
||||
.map_err(|_| "code-mode process metrics timed out".to_string())?
|
||||
}
|
||||
Reference in New Issue
Block a user