Skip to content

Commit ec3fe9c

Browse files
committed
Respond to comments on PR
1 parent 4bbecf8 commit ec3fe9c

File tree

9 files changed

+59
-55
lines changed

9 files changed

+59
-55
lines changed

exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -293,33 +293,32 @@ def _export(
293293
# FIXME remove this check if the export type for traces
294294
# gets updated to a class that represents the proto
295295
# TracesData and use the code below instead.
296-
retry_info = RetryInfo()
297296
with self._export_lock:
298297
deadline_sec = time() + self._timeout
299-
for retry_num in range(1, _MAX_RETRYS + 1):
300-
backoff_seconds = 2 ** (retry_num - 1) * random.uniform(
301-
0.8, 1.2
302-
)
298+
for retry_num in range(_MAX_RETRYS):
303299
try:
304300
self._client.Export(
305301
request=self._translate_data(data),
306302
metadata=self._headers,
307-
timeout=self._timeout,
303+
timeout=deadline_sec - time(),
308304
)
309305
return self._result.SUCCESS
310306
except RpcError as error:
311307
retry_info_bin = dict(error.trailing_metadata()).get(
312308
"google.rpc.retryinfo-bin"
313309
)
310+
# multiplying by a random number between .8 and 1.2 introduces a +/20% jitter to each backoff.
311+
backoff_seconds = 2**retry_num * random.uniform(0.8, 1.2)
314312
if retry_info_bin is not None:
313+
retry_info = RetryInfo()
315314
retry_info.ParseFromString(retry_info_bin)
316315
backoff_seconds = (
317316
retry_info.retry_delay.seconds
318317
+ retry_info.retry_delay.nanos / 1.0e9
319318
)
320319
if (
321320
error.code() not in _RETRYABLE_ERROR_CODES
322-
or retry_num == _MAX_RETRYS
321+
or retry_num + 1 == _MAX_RETRYS
323322
or backoff_seconds > (deadline_sec - time())
324323
):
325324
logger.error(

exporter/opentelemetry-exporter-otlp-proto-grpc/test-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ tomli==2.0.1
1111
typing_extensions==4.10.0
1212
wrapt==1.16.0
1313
zipp==3.19.2
14+
googleapis-common-protos==1.63.2
1415
-e opentelemetry-api
1516
-e tests/opentelemetry-test-utils
1617
-e exporter/opentelemetry-exporter-otlp-proto-common

exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_exporter_mixin.py

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -90,33 +90,32 @@ class TraceServiceServicerWithExportParams(TraceServiceServicer):
9090
def __init__(
9191
self,
9292
export_result: StatusCode,
93-
optional_retry_millis: Optional[int] = None,
93+
optional_retry_nanos: Optional[int] = None,
9494
optional_export_sleep: Optional[float] = None,
9595
):
9696
self.export_result = export_result
9797
self.optional_export_sleep = optional_export_sleep
98-
self.optional_retry_millis = optional_retry_millis
98+
self.optional_retry_nanos = optional_retry_nanos
9999
self.num_requests = 0
100100

101101
# pylint: disable=invalid-name,unused-argument
102102
def Export(self, request, context):
103103
self.num_requests += 1
104104
if self.optional_export_sleep:
105105
time.sleep(self.optional_export_sleep)
106-
if self.export_result != StatusCode.OK:
107-
if self.optional_retry_millis:
108-
context.set_trailing_metadata(
106+
if self.export_result != StatusCode.OK and self.optional_retry_nanos:
107+
context.set_trailing_metadata(
108+
(
109109
(
110-
(
111-
"google.rpc.retryinfo-bin",
112-
RetryInfo(
113-
retry_delay=Duration(
114-
nanos=self.optional_retry_millis
115-
)
116-
).SerializeToString(),
117-
),
118-
)
110+
"google.rpc.retryinfo-bin",
111+
RetryInfo(
112+
retry_delay=Duration(
113+
nanos=self.optional_retry_nanos
114+
)
115+
).SerializeToString(),
116+
),
119117
)
118+
)
120119
context.set_code(self.export_result)
121120

122121
return ExportTraceServiceResponse()
@@ -372,7 +371,8 @@ def test_export_over_closed_grpc_channel(self):
372371

373372
def test_retry_info_is_respected(self):
374373
mock_trace_service = TraceServiceServicerWithExportParams(
375-
StatusCode.UNAVAILABLE, optional_retry_millis=200
374+
StatusCode.UNAVAILABLE,
375+
optional_retry_nanos=200000000, # .2 seconds
376376
)
377377
add_TraceServiceServicer_to_server(
378378
mock_trace_service,
@@ -386,8 +386,8 @@ def test_retry_info_is_respected(self):
386386
)
387387
after = time.time()
388388
self.assertEqual(mock_trace_service.num_requests, 6)
389-
# 200 * 5 = 1 second, plus some wiggle room so the test passes consistently.
390-
self.assertTrue(after - before < 1.1)
389+
# 1 second plus wiggle room so the test passes consistently.
390+
self.assertAlmostEqual(after - before, 1, 1)
391391

392392
def test_retry_not_made_if_would_exceed_timeout(self):
393393
mock_trace_service = TraceServiceServicerWithExportParams(
@@ -408,34 +408,35 @@ def test_retry_not_made_if_would_exceed_timeout(self):
408408
# First call at time 0, second at time 1, third at time 3, fourth would exceed timeout.
409409
self.assertEqual(mock_trace_service.num_requests, 3)
410410
# There's a +/-20% jitter on each backoff.
411-
self.assertTrue(after - before < 3.7)
411+
self.assertTrue(2.35 < after - before < 3.65)
412412

413413
def test_timeout_set_correctly(self):
414414
mock_trace_service = TraceServiceServicerWithExportParams(
415-
StatusCode.OK, optional_export_sleep=0.5
415+
StatusCode.UNAVAILABLE, optional_export_sleep=0.25
416416
)
417417
add_TraceServiceServicer_to_server(
418418
mock_trace_service,
419419
self.server,
420420
)
421-
exporter = OTLPSpanExporterForTesting(insecure=True, timeout=0.4)
422-
# Should timeout. Deadline should be set to now + timeout.
423-
# That is 400 millis from now, and export sleeps for 500 millis.
421+
exporter = OTLPSpanExporterForTesting(insecure=True, timeout=1.4)
422+
# Should timeout after 1.4 seconds. First attempt takes .25 seconds
423+
# Then a 1 second sleep, then deadline exceeded after .15 seconds,
424+
# mid way through second call.
424425
with self.assertLogs(level=WARNING) as warning:
425-
self.assertEqual(
426-
exporter.export([self.span]),
427-
SpanExportResult.FAILURE,
428-
)
426+
before = time.time()
427+
# Eliminate the jitter.
428+
with patch("random.uniform", return_value=1):
429+
self.assertEqual(
430+
exporter.export([self.span]),
431+
SpanExportResult.FAILURE,
432+
)
433+
after = time.time()
429434
self.assertEqual(
430435
"Failed to export traces to localhost:4317, error code: StatusCode.DEADLINE_EXCEEDED",
431436
warning.records[-1].message,
432437
)
433-
self.assertEqual(mock_trace_service.num_requests, 1)
434-
exporter = OTLPSpanExporterForTesting(insecure=True, timeout=0.8)
435-
self.assertEqual(
436-
exporter.export([self.span]),
437-
SpanExportResult.SUCCESS,
438-
)
438+
self.assertEqual(mock_trace_service.num_requests, 2)
439+
self.assertAlmostEqual(after - before, 1.4, 1)
439440

440441
def test_otlp_headers_from_env(self):
441442
# pylint: disable=protected-access

exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/_log_exporter/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,14 +163,15 @@ def export(self, batch: Sequence[LogData]) -> LogExportResult:
163163

164164
serialized_data = encode_logs(batch).SerializeToString()
165165
deadline_sec = time() + self._timeout
166-
for retry_num in range(1, _MAX_RETRYS + 1):
167-
backoff_seconds = 2 ** (retry_num - 1) * random.uniform(0.8, 1.2)
166+
for retry_num in range(_MAX_RETRYS):
168167
resp = self._export(serialized_data, deadline_sec - time())
169168
if resp.ok:
170169
return LogExportResult.SUCCESS
170+
# multiplying by a random number between .8 and 1.2 introduces a +/20% jitter to each backoff.
171+
backoff_seconds = 2**retry_num * random.uniform(0.8, 1.2)
171172
if (
172173
not _is_retryable(resp)
173-
or retry_num == _MAX_RETRYS
174+
or retry_num + 1 == _MAX_RETRYS
174175
or backoff_seconds > (deadline_sec - time())
175176
):
176177
_logger.error(

exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/metric_exporter/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,14 +215,15 @@ def export(
215215
deadline_sec = time() + (
216216
timeout_millis / 1e3 if timeout_millis else self._timeout
217217
)
218-
for retry_num in range(1, _MAX_RETRYS + 1):
219-
backoff_seconds = 2 ** (retry_num - 1) * random.uniform(0.8, 1.2)
218+
for retry_num in range(_MAX_RETRYS):
220219
resp = self._export(serialized_data, deadline_sec - time())
221220
if resp.ok:
222221
return MetricExportResult.SUCCESS
222+
# multiplying by a random number between .8 and 1.2 introduces a +/20% jitter to each backoff.
223+
backoff_seconds = 2 ** retry_num * random.uniform(0.8, 1.2)
223224
if (
224225
not _is_retryable(resp)
225-
or retry_num == _MAX_RETRYS
226+
or retry_num + 1 == _MAX_RETRYS
226227
or backoff_seconds > (deadline_sec - time())
227228
):
228229
_logger.error(

exporter/opentelemetry-exporter-otlp-proto-http/src/opentelemetry/exporter/otlp/proto/http/trace_exporter/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,15 @@ def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
161161

162162
serialized_data = encode_spans(spans).SerializePartialToString()
163163
deadline_sec = time() + self._timeout
164-
for retry_num in range(1, _MAX_RETRYS + 1):
165-
backoff_seconds = 2 ** (retry_num - 1) * random.uniform(0.8, 1.2)
164+
for retry_num in range(_MAX_RETRYS):
166165
resp = self._export(serialized_data, deadline_sec - time())
167166
if resp.ok:
168167
return SpanExportResult.SUCCESS
168+
# multiplying by a random number between .8 and 1.2 introduces a +/20% jitter to each backoff.
169+
backoff_seconds = 2**retry_num * random.uniform(0.8, 1.2)
169170
if (
170171
not _is_retryable(resp)
171-
or retry_num == _MAX_RETRYS
172+
or retry_num + 1 == _MAX_RETRYS
172173
or backoff_seconds > (deadline_sec - time())
173174
):
174175
_logger.error(

exporter/opentelemetry-exporter-otlp-proto-http/tests/metrics/test_otlp_metrics_exporter.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ def test_retry_timeout(self, mock_post):
523523
# First call at time 0, second at time 1, then an early return before the second backoff sleep b/c it would exceed timeout.
524524
self.assertEqual(mock_post.call_count, 2)
525525
# There's a +/-20% jitter on each backoff.
526-
self.assertTrue(after - before < 1.3)
526+
self.assertTrue(0.75 < after - before < 1.25)
527527
self.assertIn(
528528
"Transient error UNAVAILABLE encountered while exporting metrics batch, retrying in",
529529
warning.records[0].message,
@@ -540,7 +540,7 @@ def test_retry_timeout(self, mock_post):
540540
# First call at time 0, second at time 1, third at time 3.
541541
self.assertEqual(mock_post.call_count, 3)
542542
# There's a +/-20% jitter on each backoff.
543-
self.assertTrue(after - before < 3.7)
543+
self.assertTrue(2.35 < after - before < 3.65)
544544
self.assertIn(
545545
"Transient error UNAVAILABLE encountered while exporting metrics batch, retrying in",
546546
warning.records[0].message,
@@ -553,7 +553,7 @@ def test_timeout_set_correctly(self, mock_post):
553553

554554
def export_side_effect(*args, **kwargs):
555555
# Timeout should be set to something slightly less than 400 milliseconds depending on how much time has passed.
556-
self.assertTrue(0.4 - kwargs["timeout"] < 0.0005)
556+
self.assertAlmostEqual(0.4, kwargs["timeout"], 2)
557557
return resp
558558

559559
mock_post.side_effect = export_side_effect

exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_log_exporter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ def test_retry_timeout(self, mock_post):
369369
# First call at time 0, second at time 1, then an early return before the second backoff sleep b/c it would exceed timeout.
370370
self.assertEqual(mock_post.call_count, 2)
371371
# There's a +/-20% jitter on each backoff.
372-
self.assertTrue(after - before < 1.3)
372+
self.assertTrue(0.75 < after - before < 1.25)
373373
self.assertIn(
374374
"Transient error UNAVAILABLE encountered while exporting logs batch, retrying in",
375375
warning.records[0].message,
@@ -382,7 +382,7 @@ def test_timeout_set_correctly(self, mock_post):
382382

383383
def export_side_effect(*args, **kwargs):
384384
# Timeout should be set to something slightly less than 400 milliseconds depending on how much time has passed.
385-
self.assertTrue(0.4 - kwargs["timeout"] < 0.0005)
385+
self.assertAlmostEqual(0.4, kwargs["timeout"], 2)
386386
return resp
387387

388388
mock_post.side_effect = export_side_effect

exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def test_retry_timeout(self, mock_post):
269269
# First call at time 0, second at time 1, then an early return before the second backoff sleep b/c it would exceed timeout.
270270
self.assertEqual(mock_post.call_count, 2)
271271
# There's a +/-20% jitter on each backoff.
272-
self.assertTrue(after - before < 1.3)
272+
self.assertTrue(0.75 < after - before < 1.25)
273273
self.assertIn(
274274
"Transient error UNAVAILABLE encountered while exporting span batch, retrying in",
275275
warning.records[0].message,
@@ -282,7 +282,7 @@ def test_timeout_set_correctly(self, mock_post):
282282

283283
def export_side_effect(*args, **kwargs):
284284
# Timeout should be set to something slightly less than 400 milliseconds depending on how much time has passed.
285-
self.assertTrue(0.4 - kwargs["timeout"] < 0.0005)
285+
self.assertAlmostEqual(0.4, kwargs["timeout"], 2)
286286
return resp
287287

288288
mock_post.side_effect = export_side_effect

0 commit comments

Comments
 (0)