remove invocation lock#894
Conversation
| pub async fn get_reparenting_info( | ||
| &self, | ||
| ) -> Result<std::collections::VecDeque<ReparentingInfo>, ProcessorError> { | ||
| let (response_tx, response_rx) = oneshot::channel(); | ||
|
|
||
| self.sender | ||
| .send(ProcessorCommand::GetReparentingInfo { | ||
| response: response_tx, | ||
| }) | ||
| .map_err(|e| ProcessorError::ChannelSend(e.to_string()))?; | ||
|
|
||
| response_rx | ||
| .await | ||
| .map_err(|e| ProcessorError::ChannelReceive(e.to_string()))? | ||
| } | ||
|
|
||
| pub async fn update_reparenting( | ||
| &self, | ||
| reparenting_info: std::collections::VecDeque<ReparentingInfo>, | ||
| ) -> Result<Vec<crate::lifecycle::invocation::context::Context>, ProcessorError> { | ||
| let (response_tx, response_rx) = oneshot::channel(); | ||
|
|
There was a problem hiding this comment.
would be great to refactor these.
There was a problem hiding this comment.
what did you have in mind?
There was a problem hiding this comment.
something like
async fn send_and_await<T, F>(
&self,
command_builder: F,
) -> Result<T, ProcessorError>
where
F: FnOnce(oneshot::Sender<Result<T, ProcessorError>>) -> ProcessorCommand,
{
let (response_tx, response_rx) = oneshot::channel();
self.sender
.send(command_builder(response_tx))
.await
.map_err(|e| ProcessorError::ChannelSend(e.to_string()))?;
response_rx
.await
.map_err(|e| ProcessorError::ChannelReceive(e.to_string()))?
}
pub async fn get_reparenting_info(
&self,
) -> Result<std::collections::VecDeque<ReparentingInfo>, ProcessorError> {
self.send_and_await(|response| ProcessorCommand::GetReparentingInfo { response })
.await
}
pub async fn update_reparenting(
&self,
reparenting_info: std::collections::VecDeque<ReparentingInfo>,
) -> Result<Vec<Context>, ProcessorError> {
self.send_and_await(|response| ProcessorCommand::UpdateReparenting {
reparenting_info,
response,
})
.await
}
Same for other places. WDYT?
| ) -> Result<Option<u64>, ProcessorError> { | ||
| let (response_tx, response_rx) = oneshot::channel(); | ||
|
|
||
| self.sender |
| .on_platform_runtime_done( | ||
| request_id.clone(), | ||
| metrics, | ||
| status, | ||
| error_type.clone(), |
There was a problem hiding this comment.
if wait_for_platform_runtime_done_completion=false, cycle could be wasted due to async. Given that it is a more frequent scenario, would we consider to use async only if necessary?
There was a problem hiding this comment.
What do you mean by cycle wasted due to async? If wait_for_platform_runtime_done_completion=false, then invocation_processor_handle.on_platform_runtime_done() should pretty much immediately return.
There was a problem hiding this comment.
while it could return right away, since it is an async call, I would imagine it will incur some overhead which doesn't happen in non-async fashion.
| } => { | ||
| self.processor | ||
| .send_ctx_spans(&tags_provider, &trace_sender, context) | ||
| .await; |
There was a problem hiding this comment.
why do we wait here, unlike other processor calls?
There was a problem hiding this comment.
oops, that is a typo, will remove 'await'
There was a problem hiding this comment.
Actually .await is needed since send_ctx_spans() is async.
litianningdatadog
left a comment
There was a problem hiding this comment.
Left some comments
| metrics_aggregator_handle: AggregatorHandle, | ||
| propagator: Arc<DatadogCompositePropagator>, | ||
| ) -> (InvocationProcessorHandle, Self) { | ||
| let (sender, receiver) = mpsc::unbounded_channel(); |
There was a problem hiding this comment.
Maybe we want to bound it to a 1000? @astuyve what would be a good number?
There was a problem hiding this comment.
Yeah, good point.
| Err(e) => { | ||
| return error_response( | ||
| StatusCode::INTERNAL_SERVER_ERROR, | ||
| format!("Failed to get reparenting info: {e}"), | ||
| ); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Not sure if we should be erroring here, maybe just logging the error is enough? What happens if it failed before?
There was a problem hiding this comment.
I guess this error is mostly when failing to send/receive from the channel?
| timestamp: i64, | ||
| wait_for_completion: bool, | ||
| ) -> Result<(), ProcessorError> { | ||
| // Only when Flush decision is 'End' do we want to wait to finish processing PlatformRuntimeDone |
There was a problem hiding this comment.
Otherwise aren't we going to start flushing events before potentially processing all of them?
duncanista
left a comment
There was a problem hiding this comment.
LGTM – the only comment is we shouldn't 500 when failing to get reparenting info
|
/merge |
|
View all feedbacks in Devflow UI.
The expected merge time in
|
https://datadoghq.atlassian.net/browse/SVLS-7991 ## Overview PR #894 introduced an asynchronous message-passing architecture that changed the timing of CPU metrics collection. This timing difference exposed a pre-existing issue where per-CPU idle time measurements could exceed the wall-clock uptime delta, resulting in negative CPU utilization values being reported to customers. The root cause is a fundamental mismatch between measurement domains: - `/proc/uptime` measures wall-clock system uptime (single value) - `/proc/stat` measures per-CPU cumulative idle time (one value per core) When these measurements are taken at slightly different times (especially in the async processing model), the per-CPU idle time delta can exceed the uptime delta, causing the formula `((uptime - idle_time) / uptime) * 100` to produce negative results. ## Solution Implemented defensive validation and enforce in the CPU utilization calculation to ensure metrics are always within valid ranges: 1. **Uptime Validation**: Skip metrics if uptime delta is invalid (≤ 0) - Prevents division by zero - Catches timing anomalies early 2. **Per-CPU Idle Time Check**: Enforce each CPU's idle time to non-negative value - Handles cases where idle_time > uptime due to measurement timing - Handles negative idle_time from measurement errors 3. **Utilization Calculation**: Force all utilization values to be non-negative value PS: Since this is a complex issue without a definitive solution yet, this fix serves only as a temporary measure to unblock our release commitment. We’ll continue investigating a long-term solution as a follow-up. ## Test - Deployed the layer w/ the change and applied them to [these stacks](https://docs.google.com/spreadsheets/d/1oF60PBhYvwdOfFn6yz3zBUhZCZUP7Z43VVE6XE2QGWQ/edit?gid=0#gid=0) as they were the main contributors of the negative stats - Observe the stats and expect [no more negative stats](https://ddserverless.datadoghq.com/dashboard/35c-u5f-8jm?fromUser=true&fullscreen_end_ts=1763142342127&fullscreen_paused=false&fullscreen_refresh_mode=sliding&fullscreen_section=overview&fullscreen_start_ts=1763138742127&fullscreen_widget=2129549723517146&refresh_mode=paused&tpl_var_runtime%5B0%5D=python3.10&tpl_var_runtime%5B1%5D=dotnet8&tpl_var_runtime%5B2%5D=java11&tpl_var_runtime%5B3%5D=nodejs20.x&tpl_var_runtime%5B4%5D=python3.13&tpl_var_runtime%5B5%5D=ruby3.2&tpl_var_service%5B0%5D=d1&from_ts=1763136901167&to_ts=1763137625000&live=false) are reported <img width="2262" height="1698" alt="image" src="https://github.com/user-attachments/assets/a4482590-64ac-4322-8169-103f82706ddf" />
https://datadoghq.atlassian.net/browse/SVLS-7991 ## Overview PR #894 introduced an asynchronous message-passing architecture that changed the timing of CPU metrics collection. This timing difference exposed a pre-existing issue where per-CPU idle time measurements could exceed the wall-clock uptime delta, resulting in negative CPU utilization values being reported to customers. The root cause is a fundamental mismatch between measurement domains: - `/proc/uptime` measures wall-clock system uptime (single value) - `/proc/stat` measures per-CPU cumulative idle time (one value per core) When these measurements are taken at slightly different times (especially in the async processing model), the per-CPU idle time delta can exceed the uptime delta, causing the formula `((uptime - idle_time) / uptime) * 100` to produce negative results. ## Solution Implemented defensive validation and enforce in the CPU utilization calculation to ensure metrics are always within valid ranges: 1. **Uptime Validation**: Skip metrics if uptime delta is invalid (≤ 0) - Prevents division by zero - Catches timing anomalies early 2. **Per-CPU Idle Time Check**: Enforce each CPU's idle time to non-negative value - Handles cases where idle_time > uptime due to measurement timing - Handles negative idle_time from measurement errors 3. **Utilization Calculation**: Force all utilization values to be non-negative value PS: Since this is a complex issue without a definitive solution yet, this fix serves only as a temporary measure to unblock our release commitment. We’ll continue investigating a long-term solution as a follow-up. ## Test - Deployed the layer w/ the change and applied them to [these stacks](https://docs.google.com/spreadsheets/d/1oF60PBhYvwdOfFn6yz3zBUhZCZUP7Z43VVE6XE2QGWQ/edit?gid=0#gid=0) as they were the main contributors of the negative stats - Observe the stats and expect [no more negative stats](https://ddserverless.datadoghq.com/dashboard/35c-u5f-8jm?fromUser=true&fullscreen_end_ts=1763142342127&fullscreen_paused=false&fullscreen_refresh_mode=sliding&fullscreen_section=overview&fullscreen_start_ts=1763138742127&fullscreen_widget=2129549723517146&refresh_mode=paused&tpl_var_runtime%5B0%5D=python3.10&tpl_var_runtime%5B1%5D=dotnet8&tpl_var_runtime%5B2%5D=java11&tpl_var_runtime%5B3%5D=nodejs20.x&tpl_var_runtime%5B4%5D=python3.13&tpl_var_runtime%5B5%5D=ruby3.2&tpl_var_service%5B0%5D=d1&from_ts=1763136901167&to_ts=1763137625000&live=false) are reported <img width="2262" height="1698" alt="image" src="https://github.com/user-attachments/assets/a4482590-64ac-4322-8169-103f82706ddf" />
Task
https://datadoghq.atlassian.net/browse/SVLS-7465?atlOrigin=eyJpIjoiYzI2ZWQ3NmU1M2U4NGFiMGI1ZjE3MWY5MTM2MzlkN2MiLCJwIjoiaiJ9
Overview
Remove InvocationProcessor lock and replace with an aggregator service.