@@ -226,6 +226,48 @@ def _export(self, serialized_data: bytes, timeout_sec: float):
226226 )
227227 return resp
228228
229+ def _export_with_retries (
230+ self ,
231+ serialized_data : bytes ,
232+ deadline_sec : float ,
233+ ) -> MetricExportResult :
234+ """Export serialized data with retry logic until success, non-transient error, or exponential backoff maxed out.
235+
236+ Args:
237+ serialized_data: serialized metrics data to export
238+ deadline_sec: timestamp deadline for the export
239+
240+ Returns:
241+ MetricExportResult: SUCCESS if export succeeded, FAILURE otherwise
242+ """
243+ for retry_num in range (_MAX_RETRYS ):
244+ resp = self ._export (serialized_data , deadline_sec - time ())
245+ if resp .ok :
246+ return MetricExportResult .SUCCESS
247+
248+ # multiplying by a random number between .8 and 1.2 introduces a +/20% jitter to each backoff.
249+ backoff_seconds = 2 ** retry_num * random .uniform (0.8 , 1.2 )
250+ if (
251+ not _is_retryable (resp )
252+ or retry_num + 1 == _MAX_RETRYS
253+ or backoff_seconds > (deadline_sec - time ())
254+ ):
255+ _logger .error (
256+ "Failed to export metrics batch code: %s, reason: %s" ,
257+ resp .status_code ,
258+ resp .text ,
259+ )
260+ return MetricExportResult .FAILURE
261+
262+ _logger .warning (
263+ "Transient error %s encountered while exporting metrics batch, retrying in %.2fs." ,
264+ resp .reason ,
265+ backoff_seconds ,
266+ )
267+ sleep (backoff_seconds )
268+
269+ return MetricExportResult .FAILURE
270+
229271 def export (
230272 self ,
231273 metrics_data : MetricsData ,
@@ -241,71 +283,23 @@ def export(
241283
242284 # If no batch size configured, export as single batch with retries as configured
243285 if self ._max_export_batch_size is None :
244- for retry_num in range (_MAX_RETRYS ):
245- resp = self ._export (
246- serialized_data .SerializeToString (), deadline_sec - time ()
247- )
248- if resp .ok :
249- return MetricExportResult .SUCCESS
250- # multiplying by a random number between .8 and 1.2 introduces a +/20% jitter to each backoff.
251- backoff_seconds = 2 ** retry_num * random .uniform (0.8 , 1.2 )
252- if (
253- not _is_retryable (resp )
254- or retry_num + 1 == _MAX_RETRYS
255- or backoff_seconds > (deadline_sec - time ())
256- ):
257- _logger .error (
258- "Failed to export metrics batch code: %s, reason: %s" ,
259- resp .status_code ,
260- resp .text ,
261- )
262- return MetricExportResult .FAILURE
263- _logger .warning (
264- "Transient error %s encountered while exporting metrics batch, retrying in %.2fs." ,
265- resp .reason ,
266- backoff_seconds ,
267- )
268- sleep (backoff_seconds )
286+ return self ._export_with_retries (
287+ serialized_data .SerializeToString (), deadline_sec
288+ )
269289
270290 # Else, export in batches of configured size
271291 split_metrics_batches = list (self ._split_metrics_data (serialized_data ))
272292 export_result = MetricExportResult .SUCCESS
273293
274294 for split_metrics_data in split_metrics_batches :
275- # Export current batch until success, non-transient error, or retries maxed out
276- for retry_num in range (_MAX_RETRYS ):
277- split_resp = self ._export (
278- split_metrics_data .SerializeToString (),
279- deadline_sec - time (),
280- )
281- if split_resp .ok :
282- export_result = MetricExportResult .SUCCESS
283- # Move on to next batch
284- break
285-
286- # multiplying by a random number between .8 and 1.2 introduces a +/20% jitter to each backoff.
287- backoff_seconds = 2 ** retry_num * random .uniform (0.8 , 1.2 )
288- if (
289- not _is_retryable (split_resp )
290- or retry_num + 1 == _MAX_RETRYS
291- or backoff_seconds > (deadline_sec - time ())
292- ):
293- _logger .error (
294- "Failed to export metrics batch code: %s, reason: %s" ,
295- split_resp .status_code ,
296- split_resp .text ,
297- )
298- export_result = MetricExportResult .FAILURE
299- # Don't retry; move on to next batch
300- break
301-
302- _logger .warning (
303- "Transient error %s encountered while exporting metric batch, retrying in %.2fs." ,
304- split_resp .reason ,
305- backoff_seconds ,
306- )
307- sleep (backoff_seconds )
308- continue
295+ batch_result = self ._export_with_retries (
296+ split_metrics_data .SerializeToString (),
297+ deadline_sec ,
298+ )
299+
300+ if batch_result == MetricExportResult .FAILURE :
301+ export_result = MetricExportResult .FAILURE
302+ # Don't retry; move on to next batch
309303
310304 # Return last result after all batches are attempted
311305 return export_result
0 commit comments