← Back to list

PulsePost: A Tiny Load Tester That Helped Me Avoid Overbuilding

A small keep-alive JSON POST script for checking API headroom before scaling infrastructure.

Alexander in Coffee☕ And Code💚 · 2026-06-01 20:29 · 0 claps · 4.2 min read
#python #performance-testing #load-testing #software-development #techtrends-digest
Open on Medium ↗

PulsePost: A Tiny Load Tester That Helped Me Avoid Overbuilding

A small keep-alive JSON POST script for checking API headroom before scaling infrastructure.

Photo by Pankaj Patel on Unsplash

Photo by Pankaj Patel on Unsplash

Before changing infrastructure for an MVP API, I wanted to answer a simple question: could the current server handle enough traffic for the current stage? Not theoretical scale, not global traffic, and not a perfect benchmark — just a practical check of whether the API and worker pipeline had obvious headroom.

I did not want to start with a full load-testing setup for that. I wanted something small enough to understand in one file, specific enough to test the endpoint I cared about, and quick enough to run before making infrastructure decisions. That became PulsePost.

The goal was a sanity check, not a benchmark suite

PulsePost is a tiny Python script for sending JSON POST requests with concurrent workers and summarizing the result. It is intentionally limited: standard library only, configurable URL, configurable worker count, keep-alive by default, random numeric payload values, status counts, p50/p95 latency, and top errors.

It is not a replacement for k6, wrk, Locust, distributed testing, browser performance testing, or long soak tests. Those tools exist for good reasons. The goal here was smaller: check whether the current API could handle a realistic short burst before redesigning infrastructure too early.

For an MVP, that can be enough. If the current server handles the expected request rate, the next best move may be shipping, improving observability, or testing with real users — not adding more infrastructure.

Keep-alive changed the result

The first version of the script opened a new TCP/TLS connection for every request. That made the numbers look worse than the API actually was, because the test was spending too much time measuring connection setup instead of endpoint behavior.

Most real clients, backend integrations, SDKs, and service-to-service calls do not intentionally create a fresh TLS connection for every request. They reuse connections. PulsePost therefore keeps one connection open per worker by default and reconnects only when needed.

That small change made the test more representative for the question I was asking: can this API handle sustained JSON POST traffic from clients that reuse connections?

Benchmark the benchmark

The more interesting lesson came after that.

With VPN enabled, the same test reported about 658 requests per second with p95 latency around 86ms. Without VPN, it reached 1,844 requests per second with p95 latency around 30ms.

The API was the same. The workers were the same. The endpoint was the same. The network path changed the result.

That is an important reminder: a quick load test does not only measure the server. It also measures the client machine, local network, VPN, region distance, TLS behavior, connection reuse, and single-client limits.

Before drawing conclusions from a small benchmark, it is worth checking whether the test client is part of the bottleneck. In this case, the difference between VPN and no VPN was large enough that using the first result alone would have led to the wrong conclusion about available headroom.

A small test run

The script can be run like this:

python pulsepost.py \
  --url https://api.example.com/v1/events/value \
  --api-key "$API_KEY" \
  --stat-name api.random_load_test \
  --workers 50 \
  --duration 60

The payload is intentionally simple and can be adjusted to match the API being tested. In my case, it sent a small metric-style event with an API key, a stat name, and a random value. The output gives just enough signal for a quick decision:

Summary
-------
Duration: 60.1s
Total requests: 110778
Successful requests: 110778
Failed requests: 0
Requests/sec: 1844.15
Status counts: {202: 110778}
Latency min: 20.6ms
Latency avg: 27.0ms
Latency p50: 25.4ms
Latency p95: 29.5ms
Latency max: 6615.1ms

The exact numbers matter less than the shape of the result. I wanted to know whether requests were accepted, whether failures appeared, whether p95 latency stayed reasonable, and whether the system behind the endpoint was keeping up.

The HTTP response was not enough

A load test can lie if you only look at the HTTP response. In this case, the endpoint accepted events and placed work onto a queue. That means a fast 202 Accepted response did not prove the whole system was healthy. The API could accept requests quickly while the queue grew forever in the background.

During the test, I watched request rate, latency, queue depth, worker throughput, CPU usage, and memory usage. The key signal was queue depth. If the API accepts requests but the queue keeps growing, the bottleneck has only moved. It has not disappeared.

That is the difference between checking an endpoint and checking the system.

What this told me

The result did not prove infinite scale. It did not prove the infrastructure would survive every traffic pattern, every region, or every long-running workload. It did answer a smaller and more useful question: for the current stage, did the API and worker pipeline have enough headroom?

In this case, yes. More importantly, the comparison between VPN and non-VPN runs reminded me not to overinterpret a single benchmark. A small test is useful, but only if you understand what it is actually measuring.

That was enough to avoid overbuilding. I did not need to redesign the infrastructure before getting users. I needed to keep shipping, keep measuring, and improve the system when the measurements showed a real reason to do so.

Caveats

PulsePost is useful because it is small, but the same thing makes it limited. One client machine can become the bottleneck. One region does not simulate global traffic. Synthetic requests do not behave like real users. A one-minute test does not replace a soak test. A POST script does not test browser performance, frontend behavior, or complex user flows.

Also, only run load tests against systems you own or have explicit permission to test. Even a small script can create real traffic and real operational impact.

Final thought

Before scaling, measure. Before trusting the measurement, check the measurement path.

Sometimes the test client, VPN, local network, or connection behavior can change the result enough to mislead you. A small script can still be useful, but only if you treat it as a sanity check rather than a final verdict.

PulsePost is not meant to be a load-testing platform. It is a quick way to ask one practical question: does this API have enough headroom right now?


메타데이터
post_id
8cd98ab9707a
slug
pulsepost-a-tiny-load-tester-that-helped-me-avoid-overbuilding-8cd98ab9707a
url
https://medium.com/techtrends-digest/pulsepost-a-tiny-load-tester-that-helped-me-avoid-overbuilding-8cd98ab9707a
canonical_url
https://medium.com/techtrends-digest/pulsepost-a-tiny-load-tester-that-helped-me-avoid-overbuilding-8cd98ab9707a
author_url
https://medium.com/@lexpank
status
ok
fetched_at
2026-06-14 11:28:49