mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] Instrument rollout persistence bytes (#29498)
- Add 1%-sampled rollout persistence metrics that report per-item and per-thread JSON byte totals before and after filtering when metrics export is enabled. - Tag each item with its exact response or event variant, including nested turn-item kinds for conditionally persisted completion events, so aggregate cloud-storage impact can be estimated by policy choice.
This commit is contained in:
@@ -4,6 +4,8 @@ use std::sync::Arc;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::protocol::RolloutItem;
|
||||
use codex_protocol::protocol::ThreadMemoryMode;
|
||||
use codex_rollout::RolloutPersistenceTelemetry;
|
||||
use codex_rollout::measure_and_filter_rollout_items;
|
||||
use codex_rollout::persisted_rollout_items;
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::warn;
|
||||
@@ -32,6 +34,7 @@ pub struct LiveThread {
|
||||
thread_id: ThreadId,
|
||||
thread_store: Arc<dyn ThreadStore>,
|
||||
metadata_sync: Arc<Mutex<ThreadMetadataSync>>,
|
||||
persistence_telemetry: RolloutPersistenceTelemetry,
|
||||
}
|
||||
|
||||
/// Owns a live thread while session initialization is still fallible.
|
||||
@@ -95,6 +98,7 @@ impl LiveThread {
|
||||
thread_id,
|
||||
thread_store,
|
||||
metadata_sync: Arc::new(Mutex::new(metadata_sync)),
|
||||
persistence_telemetry: RolloutPersistenceTelemetry::new(thread_id),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -130,6 +134,7 @@ impl LiveThread {
|
||||
thread_id,
|
||||
thread_store,
|
||||
metadata_sync: Arc::new(Mutex::new(metadata_sync)),
|
||||
persistence_telemetry: RolloutPersistenceTelemetry::new(thread_id),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -139,16 +144,25 @@ impl LiveThread {
|
||||
fields(item_count = items.len())
|
||||
)]
|
||||
pub async fn append_items(&self, items: &[RolloutItem]) -> ThreadStoreResult<()> {
|
||||
let canonical_items = persisted_rollout_items(items);
|
||||
// Empty appends are intentionally ignored rather than represented as zero-sized batches.
|
||||
if items.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let (canonical_items, measurement) = if self.persistence_telemetry.is_enabled() {
|
||||
let (canonical_items, measurement) = measure_and_filter_rollout_items(items);
|
||||
(canonical_items, Some(measurement))
|
||||
} else {
|
||||
(persisted_rollout_items(items), None)
|
||||
};
|
||||
self.thread_store
|
||||
.append_items(AppendThreadItemsParams {
|
||||
thread_id: self.thread_id,
|
||||
items: items.to_vec(),
|
||||
})
|
||||
.await?;
|
||||
if let Some(measurement) = measurement.as_ref() {
|
||||
self.persistence_telemetry.record_batch(items, measurement);
|
||||
}
|
||||
if canonical_items.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ use crate::ResumeThreadParams;
|
||||
use crate::ThreadStoreError;
|
||||
use crate::ThreadStoreResult;
|
||||
|
||||
const ROLLOUT_SIZE_BYTES_METRIC: &str = "codex.rollout.size_bytes";
|
||||
|
||||
pub(super) async fn create_thread(
|
||||
store: &LocalThreadStore,
|
||||
params: CreateThreadParams,
|
||||
@@ -128,8 +130,15 @@ pub(super) async fn shutdown_thread(
|
||||
thread_id: ThreadId,
|
||||
) -> ThreadStoreResult<()> {
|
||||
let recorder = store.live_recorder(thread_id).await?;
|
||||
let rollout_path = recorder.rollout_path().to_path_buf();
|
||||
recorder.shutdown().await.map_err(thread_store_io_error)?;
|
||||
sync_materialized_rollout_path(store, thread_id).await?;
|
||||
if let Some(metrics) = codex_otel::global()
|
||||
&& let Ok(metadata) = tokio::fs::metadata(rollout_path).await
|
||||
{
|
||||
let size_bytes = i64::try_from(metadata.len()).unwrap_or(i64::MAX);
|
||||
let _ = metrics.histogram(ROLLOUT_SIZE_BYTES_METRIC, size_bytes, &[]);
|
||||
}
|
||||
store.live_recorders.lock().await.remove(&thread_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user