mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-12 14:10:19 +08:00
A local stream attempt writes its `usage` row and its `request_candidates` slot as `pending` in `execute_execution_runtime_stream_inner`, then awaits the provider's response headers. Everything after that point runs inside the downstream request future, so a client disconnect drops it: the dispatch `.await` never resumes and nothing settles either row. The stream finalizer that already covers this only exists once upstream headers have arrived, so the pre-first-byte window has no owner at all. Both rows stay `pending` until the maintenance sweeper rewrites them as a 504 timeout ten minutes later, losing the real outcome, the real latency, and the 499. `AttemptCancellationGuard` takes that window. It is created disarmed, so an attempt dropped before it owns any row does not grow a settlement row it never had; it is armed as soon as the attempt owns its non-terminal rows, and the stream wrappers disarm it the moment the attempt returns, from where settlement belongs to the transport. On a cancelling drop it settles the candidate slot through the same snapshot writer the `pending` write above it uses, and the usage row through a terminal `Cancelled` event. The guard outlives the request future, so what it captures is retained for the whole attempt. It therefore holds no request body: the plan carries the provider request body and the report context carries the client request body, and keeping both would double the request-body residency of every in-flight stream attempt to serve a path that almost never runs. Simply omitting them is not safe either, because a terminal write is body-capture-authoritative: with both absent the seed carries the typed `none` marker, which clears the stored capture rather than leaving it alone. `build_usage_event_data_seed_describing_request_bodies` is the third option -- it derives every capture state, body reference, request type and derived request fact from the real plan and report context, and leaves out only the two body values -- so the guard's snapshot is small and its terminal write preserves the capture the `pending` write recorded. The stream candidate first-byte watchdog also drops the attempt future, but it settles the attempt itself through `build_transport_error_stop_response`. It now marks the attempt abandoned before returning so the guard stands down instead of racing a 499 against the watchdog's 504. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
69 lines
3.2 KiB
Rust
69 lines
3.2 KiB
Rust
mod body_capture;
|
|
pub mod config;
|
|
pub mod event;
|
|
mod executor;
|
|
mod keyed_lock;
|
|
pub mod queue;
|
|
pub mod record;
|
|
pub mod report;
|
|
pub mod report_context;
|
|
mod request_metadata;
|
|
pub mod runtime;
|
|
pub mod settlement;
|
|
pub mod standardized_usage;
|
|
pub mod usage_mapper;
|
|
pub mod worker;
|
|
pub mod write;
|
|
|
|
pub use body_capture::{
|
|
apply_usage_body_capture_policy_to_event, apply_usage_body_capture_policy_to_record,
|
|
UsageBodyCaptureEngine,
|
|
};
|
|
pub use config::UsageRuntimeConfig;
|
|
pub use event::{now_ms, UsageEvent, UsageEventData, UsageEventType, USAGE_EVENT_VERSION};
|
|
pub use queue::UsageQueue;
|
|
pub use record::build_upsert_usage_record_from_event;
|
|
pub use report::{
|
|
extract_gemini_file_mapping_entries, gemini_file_mapping_cache_key,
|
|
infer_internal_finalize_signature, is_local_ai_stream_report_kind,
|
|
is_local_ai_sync_report_kind, normalize_gemini_file_name, report_request_id,
|
|
resolve_internal_finalize_route, should_handle_local_stream_report,
|
|
should_handle_local_sync_report, stream_capture_terminal_state,
|
|
stream_report_missing_terminal_event, stream_report_represents_failure,
|
|
stream_report_requires_observed_terminal_event, sync_report_represents_failure,
|
|
GatewayStreamReportRequest, GatewaySyncReportRequest, GeminiFileMappingEntry,
|
|
InternalFinalizeRoute, StreamCapturedTerminalState, GEMINI_FILE_MAPPING_TTL_SECONDS,
|
|
STREAM_MISSING_TERMINAL_EVENT_CATEGORY, STREAM_MISSING_TERMINAL_EVENT_MESSAGE,
|
|
STREAM_TERMINAL_ERROR_CATEGORY, STREAM_TERMINAL_ERROR_MESSAGE,
|
|
};
|
|
pub use report_context::{
|
|
build_locally_actionable_report_context_from_request_candidate,
|
|
build_locally_actionable_report_context_from_video_task, report_context_is_locally_actionable,
|
|
};
|
|
pub use runtime::{
|
|
UsageBillingEventEnricher, UsageBodyCapturePolicy, UsageQueueHealthSnapshot,
|
|
UsageRequestRecordLevel, UsageRuntime, UsageRuntimeAccess, UsageRuntimeMetricsSnapshot,
|
|
DEFAULT_USAGE_REQUEST_BODY_CAPTURE_LIMIT_BYTES,
|
|
DEFAULT_USAGE_RESPONSE_BODY_CAPTURE_LIMIT_BYTES,
|
|
};
|
|
pub use settlement::{settle_usage_if_needed, UsageSettlementWriter};
|
|
pub use standardized_usage::StandardizedUsage;
|
|
pub use usage_mapper::{map_usage, map_usage_from_response, UsageMapper};
|
|
pub use worker::{
|
|
build_usage_queue_worker, write_event_record, ManualProxyNodeCounter, UsageDataEventRecorder,
|
|
UsageEventRecorder, UsageQueueWorker, UsageRecordWriter,
|
|
};
|
|
pub use write::{
|
|
build_lifecycle_usage_seed, build_pending_usage_record, build_pending_usage_record_from_seed,
|
|
build_stream_terminal_usage_event, build_stream_terminal_usage_outcome,
|
|
build_stream_terminal_usage_payload_seed, build_stream_terminal_usage_seed,
|
|
build_streaming_usage_record, build_streaming_usage_record_from_seed,
|
|
build_sync_terminal_usage_event, build_sync_terminal_usage_outcome,
|
|
build_sync_terminal_usage_payload_seed, build_sync_terminal_usage_seed,
|
|
build_terminal_usage_context_seed, build_terminal_usage_event_from_outcome,
|
|
build_terminal_usage_event_from_seed, build_usage_event_data_seed,
|
|
build_usage_event_data_seed_describing_request_bodies, LifecycleUsageSeed,
|
|
StreamTerminalUsagePayloadSeed, SyncTerminalUsagePayloadSeed, TerminalUsageContextSeed,
|
|
TerminalUsageOutcome, TerminalUsageSeed, UsageTerminalState,
|
|
};
|