22
33use std:: sync:: Arc ;
44
5- use tokio:: sync:: Mutex as TokioMutex ;
65use tracing:: { debug, error} ;
76
87use dogstatsd:: {
@@ -29,7 +28,7 @@ pub struct FlushingService {
2928 trace_flusher : Arc < TraceFlusher > ,
3029 stats_flusher : Arc < StatsFlusher > ,
3130 proxy_flusher : Arc < ProxyFlusher > ,
32- metrics_flushers : Arc < TokioMutex < Vec < MetricsFlusher > > > ,
31+ metrics_flushers : Arc < Vec < MetricsFlusher > > ,
3332
3433 // Metrics aggregator handle for getting data to flush
3534 metrics_aggr_handle : MetricsAggregatorHandle ,
@@ -46,7 +45,7 @@ impl FlushingService {
4645 trace_flusher : Arc < TraceFlusher > ,
4746 stats_flusher : Arc < StatsFlusher > ,
4847 proxy_flusher : Arc < ProxyFlusher > ,
49- metrics_flushers : Arc < TokioMutex < Vec < MetricsFlusher > > > ,
48+ metrics_flushers : Arc < Vec < MetricsFlusher > > ,
5049 metrics_aggr_handle : MetricsAggregatorHandle ,
5150 ) -> Self {
5251 Self {
@@ -90,22 +89,17 @@ impl FlushingService {
9089
9190 // Spawn metrics flush
9291 // First get the data from aggregator, then spawn flush tasks for each flusher
93- let ( metrics_flushers_copy, series, sketches) = {
94- let locked_metrics = self . metrics_flushers . lock ( ) . await ;
95- let flush_response = self
96- . metrics_aggr_handle
97- . clone ( )
98- . flush ( )
99- . await
100- . expect ( "can't flush metrics handle" ) ;
101- (
102- locked_metrics. clone ( ) ,
103- flush_response. series ,
104- flush_response. distributions ,
105- )
106- } ;
92+ let flush_response = self
93+ . metrics_aggr_handle
94+ . clone ( )
95+ . flush ( )
96+ . await
97+ . expect ( "can't flush metrics handle" ) ;
98+ let series = flush_response. series ;
99+ let sketches = flush_response. distributions ;
107100
108- for ( idx, mut flusher) in metrics_flushers_copy. into_iter ( ) . enumerate ( ) {
101+ for ( idx, flusher) in self . metrics_flushers . iter ( ) . enumerate ( ) {
102+ let flusher = flusher. clone ( ) ;
109103 let series_clone = series. clone ( ) ;
110104 let sketches_clone = sketches. clone ( ) ;
111105 let handle = tokio:: spawn ( async move {
@@ -240,8 +234,7 @@ impl FlushingService {
240234 retry_batch. sketches. len( )
241235 ) ;
242236 joinset. spawn ( async move {
243- let mut locked_flushers = mf. lock ( ) . await ;
244- if let Some ( flusher) = locked_flushers. get_mut ( retry_batch. flusher_id ) {
237+ if let Some ( flusher) = mf. get ( retry_batch. flusher_id ) {
245238 flusher
246239 . flush_metrics ( retry_batch. series , retry_batch. sketches )
247240 . await ;
@@ -288,34 +281,42 @@ impl FlushingService {
288281 flush_error
289282 }
290283
291- /// Performs a blocking flush of all data.
284+ /// Performs a blocking flush of all telemetry data.
292285 ///
293- /// This method flushes all data synchronously using `tokio::join!` for parallelism.
294- /// Unlike `spawn_non_blocking`, this waits for all flushes to complete before returning.
286+ /// Flushes logs, metrics (series and distributions), traces, stats, and APM proxy
287+ /// data in parallel using `tokio::join!`. Unlike `spawn_non_blocking`, this waits
288+ /// for all flushes to complete before returning.
295289 ///
296- /// # Arguments
290+ /// The stats flusher respects its normal timing constraints (time-based bucketing),
291+ /// which may result in some stats being held back until the next flush cycle.
292+ pub async fn flush_blocking ( & self ) {
293+ self . flush_blocking_inner ( false ) . await ;
294+ }
295+
296+ /// Performs a final blocking flush of all telemetry data before shutdown.
297297 ///
298- /// * `force_stats` - If `true`, forces the stats flusher to flush immediately
299- /// regardless of timing constraints.
300- /// * `metrics_flushers` - Mutable slice of metrics flushers. The caller must acquire
301- /// the lock before calling this method.
298+ /// Flushes logs, metrics (series and distributions), traces, stats, and APM proxy
299+ /// data in parallel. Unlike `flush_blocking`, this forces the stats flusher to
300+ /// flush immediately regardless of its normal timing constraints.
302301 ///
303- /// # Note
302+ /// Use this during shutdown when this is the last opportunity to send data.
303+ pub async fn flush_blocking_final ( & self ) {
304+ self . flush_blocking_inner ( true ) . await ;
305+ }
306+
307+ /// Internal implementation for blocking flush operations.
304308 ///
305- /// TODO: The caller must acquire the lock on `metrics_flushers` and pass a mutable slice
306- /// because `MetricsFlusher::flush_metrics` requires `&mut self`. This creates awkward
307- /// ergonomics. Consider modifying the `dogstatsd` crate to use interior mutability
308- /// (e.g., `Arc<Mutex<...>>` internally) so `flush_metrics` can take `&self`, allowing
309- /// this method to handle locking internally.
310- pub async fn flush_blocking ( & self , force_stats : bool , metrics_flushers : & mut [ MetricsFlusher ] ) {
309+ /// Fetches metrics from the aggregator and flushes all data types in parallel.
310+ async fn flush_blocking_inner ( & self , force_stats : bool ) {
311311 let flush_response = self
312312 . metrics_aggr_handle
313313 . flush ( )
314314 . await
315315 . expect ( "can't flush metrics aggr handle" ) ;
316316
317- let metrics_futures: Vec < _ > = metrics_flushers
318- . iter_mut ( )
317+ let metrics_futures: Vec < _ > = self
318+ . metrics_flushers
319+ . iter ( )
319320 . map ( |f| {
320321 f. flush_metrics (
321322 flush_response. series . clone ( ) ,
@@ -332,15 +333,6 @@ impl FlushingService {
332333 self . proxy_flusher. flush( None ) ,
333334 ) ;
334335 }
335-
336- /// Returns a reference to the metrics flushers mutex for external locking.
337- ///
338- /// This is useful when you need to lock the metrics flushers and pass them
339- /// to `flush_blocking` or `flush_blocking_with_interval`.
340- #[ must_use]
341- pub fn metrics_flushers ( & self ) -> & Arc < TokioMutex < Vec < MetricsFlusher > > > {
342- & self . metrics_flushers
343- }
344336}
345337
346338impl std:: fmt:: Debug for FlushingService {
0 commit comments