Skip to content

Commit bd8a5f0

Browse files
committed
Add benches for nats-client
Signed-off-by: Casper Beyer <[email protected]>
1 parent a5dc995 commit bd8a5f0

File tree

3 files changed

+191
-0
lines changed

3 files changed

+191
-0
lines changed

nats-client/benches/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Benchmarks for nats-client package."""
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""Benchmarks for NATS client operations."""
2+
3+
import asyncio
4+
5+
import pytest
6+
from nats.client import connect
7+
from nats.server import run
8+
9+
10+
@pytest.mark.parametrize(
11+
"size",
12+
[
13+
1,
14+
2,
15+
4,
16+
8,
17+
16,
18+
32,
19+
64,
20+
128,
21+
256,
22+
512,
23+
1024,
24+
2048,
25+
4096,
26+
8192,
27+
16384,
28+
32768,
29+
],
30+
)
31+
def test_bench_publish(benchmark, size):
32+
"""Benchmark publish with various payload sizes."""
33+
subject = "bench.publish"
34+
payload = b"x" * size
35+
36+
# Adjust count based on message size to keep total data volume consistent
37+
# Target ~10MB total per benchmark run
38+
target_bytes = 10 * 1024 * 1024
39+
count = max(1, target_bytes // max(1, size))
40+
41+
def setup():
42+
loop = asyncio.new_event_loop()
43+
asyncio.set_event_loop(loop)
44+
server = loop.run_until_complete(run(port=0))
45+
client = loop.run_until_complete(connect(server.client_url))
46+
return ((loop, server, client), {})
47+
48+
def execute(loop, server, client):
49+
async def publish_n():
50+
for _ in range(count):
51+
await client.publish(subject, payload)
52+
53+
loop.run_until_complete(publish_n())
54+
55+
def teardown(loop, server, client):
56+
loop.run_until_complete(client.close())
57+
loop.run_until_complete(server.shutdown())
58+
loop.close()
59+
asyncio.set_event_loop(None)
60+
61+
benchmark.extra_info["message_size"] = size
62+
benchmark.extra_info["message_count"] = count
63+
64+
result = benchmark.pedantic(execute, setup=setup, teardown=teardown, iterations=1, rounds=1)
65+
return result
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
"""Benchmarks for NATS protocol encoding operations."""
2+
3+
import pytest
4+
from nats.client.protocol import command
5+
6+
7+
def test_bench_encode_connect(benchmark):
8+
"""Benchmark encoding CONNECT command with basic connection info."""
9+
connect_info = {
10+
"verbose": False,
11+
"pedantic": False,
12+
"tls_required": False,
13+
"name": "test-client",
14+
"lang": "python",
15+
"version": "1.0.0",
16+
"protocol": 1,
17+
}
18+
19+
benchmark(command.encode_connect, connect_info)
20+
21+
22+
@pytest.mark.parametrize("size", [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192])
23+
def test_bench_encode_pub_with_payload(benchmark, size):
24+
"""Benchmark encoding PUB command with various payload sizes."""
25+
subject = "test.subject"
26+
payload = b"x" * size
27+
28+
benchmark(command.encode_pub, subject, payload)
29+
30+
31+
def test_bench_encode_pub_with_reply(benchmark):
32+
"""Benchmark encoding PUB command with reply subject."""
33+
subject = "test.subject"
34+
payload = b"hello world"
35+
reply_to = "reply.subject"
36+
37+
benchmark(command.encode_pub, subject, payload, reply_to=reply_to)
38+
39+
40+
def test_bench_encode_hpub_single_header(benchmark):
41+
"""Benchmark encoding HPUB command with single header."""
42+
subject = "test.subject"
43+
payload = b"hello world"
44+
headers = {"X-Custom": "value"}
45+
46+
benchmark(command.encode_hpub, subject, payload, headers=headers)
47+
48+
49+
def test_bench_encode_hpub_multiple_headers(benchmark):
50+
"""Benchmark encoding HPUB command with multiple headers."""
51+
subject = "test.subject"
52+
payload = b"hello world"
53+
headers = {
54+
"X-Custom-1": "value1",
55+
"X-Custom-2": "value2",
56+
"X-Custom-3": "value3",
57+
"Content-Type": "application/json",
58+
"X-Request-ID": "12345-67890-abcdef",
59+
}
60+
61+
benchmark(command.encode_hpub, subject, payload, headers=headers)
62+
63+
64+
def test_bench_encode_hpub_multivalue_headers(benchmark):
65+
"""Benchmark encoding HPUB command with multi-value headers."""
66+
subject = "test.subject"
67+
payload = b"hello world"
68+
headers = {
69+
"X-Custom": ["value1", "value2", "value3"],
70+
"X-Tags": ["tag1", "tag2", "tag3", "tag4"],
71+
}
72+
73+
benchmark(command.encode_hpub, subject, payload, headers=headers)
74+
75+
76+
def test_bench_encode_hpub_with_reply(benchmark):
77+
"""Benchmark encoding HPUB command with reply subject and headers."""
78+
subject = "test.subject"
79+
payload = b"hello world"
80+
reply_to = "reply.subject"
81+
headers = {"X-Custom": "value"}
82+
83+
benchmark(command.encode_hpub, subject, payload, reply_to=reply_to, headers=headers)
84+
85+
86+
def test_bench_encode_sub(benchmark):
87+
"""Benchmark encoding SUB command."""
88+
subject = "test.subject"
89+
sid = "1"
90+
91+
benchmark(command.encode_sub, subject, sid)
92+
93+
94+
def test_bench_encode_sub_with_queue(benchmark):
95+
"""Benchmark encoding SUB command with queue group."""
96+
subject = "test.subject"
97+
sid = "1"
98+
queue_group = "test-queue"
99+
100+
benchmark(command.encode_sub, subject, sid, queue_group)
101+
102+
103+
def test_bench_encode_unsub(benchmark):
104+
"""Benchmark encoding UNSUB command."""
105+
sid = "1"
106+
107+
benchmark(command.encode_unsub, sid)
108+
109+
110+
def test_bench_encode_unsub_with_max(benchmark):
111+
"""Benchmark encoding UNSUB command with max_msgs."""
112+
sid = "1"
113+
max_msgs = 100
114+
115+
benchmark(command.encode_unsub, sid, max_msgs)
116+
117+
118+
def test_bench_encode_ping(benchmark):
119+
"""Benchmark encoding PING command."""
120+
benchmark(command.encode_ping)
121+
122+
123+
def test_bench_encode_pong(benchmark):
124+
"""Benchmark encoding PONG command."""
125+
benchmark(command.encode_pong)

0 commit comments

Comments
 (0)