Skip to content

Commit cdb106d

Browse files
committed
test(overhead): measure best-of-N interleaved rounds to resist CI noise
The GR-8 codec overhead check flaked on a shared runner (2.13% vs the 2% budget). Rounds are now interleaved and the best of nine is compared; the budget and reference are unchanged. Also correct the mypy ignore code on the optional confluent_kafka import.
1 parent 2230b20 commit cdb106d

2 files changed

Lines changed: 27 additions & 12 deletions

File tree

‎src/babelqueue/kafka_transport.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ def _seek_back(self, queue: str, handle: Any) -> None:
281281
except ImportError: # only reachable with an injected consumer
282282
from collections import namedtuple
283283

284-
TopicPartition = namedtuple("TopicPartition", "topic partition offset") # type: ignore[misc]
284+
TopicPartition = namedtuple("TopicPartition", "topic partition offset") # type: ignore[misc,no-redef]
285285
topic, partition, offset = handle.topic(), handle.partition(), handle.offset()
286286
try:
287287
self._consumer(queue).seek(TopicPartition(topic, partition, offset))

‎tests/test_overhead.py‎

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
"""GR-8 budget: the envelope encode/decode path must add no more than 2% over plain
22
JSON serialization (the baseline a publisher already pays), measured against a
33
conservative broker round-trip. Pure CPU — no broker — so the gate is stable and
4-
environment-independent in CI. Same methodology + reference as every other SDK.
4+
environment-independent in CI. Same reference as every other SDK; timing is best-of-N
5+
(interleaved rounds) to resist shared-runner noise.
56
"""
67

78
import json
89
import time
9-
from typing import Callable
10+
from typing import Callable, List, Sequence
1011

1112
from babelqueue import EnvelopeCodec
1213

@@ -19,14 +20,27 @@
1920
_DATA = {"order_id": 1042, "amount": 99.9, "currency": "USD", "note": "café ☕"}
2021

2122

22-
def _ns_per_op(fn: Callable[[], None]) -> float:
23-
for _ in range(5_000): # warm up
24-
fn()
25-
iterations = 50_000
26-
start = time.perf_counter_ns()
27-
for _ in range(iterations):
28-
fn()
29-
return (time.perf_counter_ns() - start) / iterations
23+
def _best_ns_per_op(
24+
fns: Sequence[Callable[[], None]], rounds: int = 9, iterations: int = 10_000
25+
) -> List[float]:
26+
"""Best-of-N per-op time for each fn (the `timeit` recommendation).
27+
28+
Scheduler preemption and noisy neighbours on shared CI runners only ever make a
29+
round slower, never faster, so the minimum across several short rounds is the
30+
closest estimate of the true cost. Rounds are interleaved across the functions so a
31+
throttling window hits all of them alike instead of skewing just one.
32+
"""
33+
for fn in fns:
34+
for _ in range(5_000): # warm up
35+
fn()
36+
best = [float("inf")] * len(fns)
37+
for _ in range(rounds):
38+
for i, fn in enumerate(fns):
39+
start = time.perf_counter_ns()
40+
for _ in range(iterations):
41+
fn()
42+
best[i] = min(best[i], (time.perf_counter_ns() - start) / iterations)
43+
return best
3044

3145

3246
def test_codec_overhead_within_budget() -> None:
@@ -36,7 +50,8 @@ def envelope() -> None:
3650
def bare() -> None:
3751
json.loads(json.dumps(_DATA))
3852

39-
marginal = max(0.0, _ns_per_op(envelope) - _ns_per_op(bare))
53+
envelope_ns, bare_ns = _best_ns_per_op([envelope, bare])
54+
marginal = max(0.0, envelope_ns - bare_ns)
4055
overhead = marginal / REFERENCE_BROKER_ROUNDTRIP_NS * 100
4156

4257
assert overhead <= 2.0, (

0 commit comments

Comments
 (0)