QA Interview Hub · Knowledge base · Quizzes

API

Performance and reliability

Kinds of load tests and percentiles

TypeWhat we doWhat we look for
LoadThe expected working load for a long timeWhether we hold the SLA under normal conditions
StressGradually raise the load above normalThe breaking point and how the system degrades
SpikeA sudden jump, for example 10 times in a minuteWhether it withstands the spike and recovers
SoakA moderate load for many hoursMemory leaks, connection pool exhaustion

Tools: k6, JMeter, Gatling, Locust.

Why not the average. An average time of 200 ms may hide that every twentieth request takes 5 seconds. So percentiles are used: p95 means 95% of requests are faster than this value, p99 means 99%. An SLA is usually worded like this: "p95 < 500 ms at 200 RPS, errors under 0.1%". The p99 tail often hurts the most, because one page makes dozens of requests, and someone almost always hits a slow one.

It is important to test on an environment close to production with realistic data: on an empty database everything is fast.

In an interview: Load checks the expected load, stress looks for the limit, spike a sudden burst, and soak stability over a long time. I evaluate p95 and p99, not the average, because the average hides the slow tail.

Timeouts, retries and idempotency keys

Timeouts. Every call to another service must have a timeout, otherwise one hung service holds threads and connections, and everything falls down. I test that with a slow dependency the client gets a controlled error (often a 504 from the gateway) in a predictable time and doesn't hang for a minute.

Retries with backoff. Only temporary errors may be repeated: a timeout, 429, 502, 503, 504. On 400 or 422 a retry is pointless: the result won't change. Retries are done with exponential backoff (1 s, 2 s, 4 s) and jitter, a random offset, so that thousands of clients don't hit the server at once. The number of attempts is limited.

Idempotency keys. Retrying a non-idempotent POST is dangerous: a timeout doesn't mean the request wasn't executed, maybe only the response was lost. So the client generates an Idempotency-Key once per operation and passes it in all repeats, and the server returns the stored result instead of a second payment.

A fintech test case: emulate a response timeout (for example through a proxy or a mock of the dependency), wait for the client's retry and check in the database that there is one transfer.

In an interview: I check that calls have timeouts, and that retries happen only on temporary errors with exponential backoff and jitter. For payments every retry goes with the same Idempotency-Key, and I check that there is one transaction in the database.

429, 503, Retry-After and the circuit breaker

429 Too Many Requests means the client exceeded a limit. 503 Service Unavailable means the service temporarily can't process the request: overload, a deploy, a dependency is down. Both may have the Retry-After header: the number of seconds or a date after which it is worth repeating:

HTTP/1.1 429 Too Many Requests
Retry-After: 30

A correct client respects Retry-After and doesn't retry earlier. What I check: the limit fires at the right threshold; the header is present and has a valid value; after the pause requests go through again; the client (our front end or service) shows a clear message instead of spinning a loader forever.

A circuit breaker is a fuse between services. If a dependency fails again and again, the breaker "opens" (the open state), and calls to it immediately return an error or a fallback without waiting for the timeout. After some time it lets a few trial requests through (half-open): if they succeed, it closes again (closed). This stops the failure of one service from bringing down the whole system in a cascade.

For QA these are resilience scenarios: turn off or slow down a dependency and check that the main service responds quickly with a controlled error or a fallback, and that after the dependency recovers everything returns to normal without manual intervention.

In an interview: On 429 and 503 I check for Retry-After and that the client respects it. A circuit breaker, after a series of failures, stops going to the dependency and quickly returns an error or a fallback, and I test this by turning off the dependency and checking recovery.