cswork / libraryOpen practice workspace

Articles

HAProxy Interview Questions: Health Checks, Timeouts, and Session Persistence

Practice HAProxy interview questions on active health checks, distinct timeout phases, sticky sessions, and safe failure diagnosis using request traces.

A HAProxy interview question often begins with “users are getting errors,” but three different mechanisms may be involved. A health check determines whether a backend should receive new traffic. A timeout bounds waiting or inactivity at a particular connection stage. Session persistence chooses the same backend for repeated requests when that routing policy still makes sense. A strong answer keeps those signals separate, then traces one failing request through them.

The HAProxy health-check guide, session-persistence guide, and configuration manual supply official behavior. The incident traces and interview prompts here are editorial exercises, not candidate reports about a named company. For a transferable design prompt, use Design a Software Load Balancer and state what health, capacity, and stickiness mean for its workload.

Interview question: what does a healthy backend prove?

An active health check probes a server on a schedule. In HAProxy, a server line can enable checks, and HTTP checks can request an endpoint and evaluate its response. The official health-check tutorial explains check configuration and thresholds. A successful TCP connection proves less than an application readiness endpoint. Even an HTTP 200 may be shallow if the endpoint never touches the database or critical dependency the user path needs.

Suppose three backends serve checkout. Backend B's /ready endpoint fails. After the configured failure threshold, HAProxy marks B down and stops choosing it for new traffic; the other healthy servers can continue receiving requests. That does not mean all existing requests on B are magically replayed or that checkout is available at full capacity. It means the load balancer's configured health signal currently excludes B. If the check itself is noisy, the proxy may flap between states, so discuss check interval plus the fall and rise thresholds before declaring a server dead after one failure.

A useful answer distinguishes liveness, readiness, and capacity. A process can be alive but not ready for new requests. A ready backend may still be overloaded. A health endpoint that tests every dependency can create a cascading outage when a shared dependency has a transient problem. Choose a check that represents the backend's ability to serve the traffic it will receive, and test it under a partial failure. This is design inference informed by HAProxy's probing mechanism, not a claim that HAProxy chooses your business health contract.

How do you read a health-check configuration?

Take a schematic HTTP backend:

backend checkout
  mode http
  balance roundrobin
  option httpchk GET /ready
  http-check expect status 200
  server app1 10.0.0.11:8080 check inter 2s fall 3 rise 2
  server app2 10.0.0.12:8080 check inter 2s fall 3 rise 2

Explain what each line contributes rather than treating the whole block as “high availability.” The check sends an HTTP request; the expect line defines the response criterion; inter sets cadence; fall and rise set consecutive thresholds for down and up transitions. A backend can still return a 500 on a different route even while /ready passes. If the application needs a specific Host header or authentication context for readiness, the check has to match that contract. Always validate syntax against the deployed HAProxy version and run a configuration check before rollout.

The operational interview follow-up is: “How quickly will B be removed?” Do not answer with a universal fixed number. The timing depends on check interval, thresholds, check duration, and when failure occurs relative to the next probe. The useful answer is an approximate upper-bound calculation under stated assumptions and the acknowledgment that existing connections have their own lifecycle.

Which timeout fired?

The official configuration manual distinguishes timeouts such as connect, queue, client, and server. Connect bounds establishing a connection to an upstream server. Queue bounds waiting for a server slot when capacity is constrained. Client and server timeouts govern inactivity on their respective sides under the configured mode and connection state. An HTTP request timeout and a tunnel timeout may be relevant for other traffic patterns. Do not describe all of them as one total end-to-end deadline.

Suppose a request waited 5 seconds before any backend connection attempt. Increasing timeout server will not fix that queue wait. Suppose the TCP handshake to a backend never completes; inspect connect timeout, network reachability, and retries. Suppose the server accepts the connection but stops sending data; investigate server-side inactivity, application logs, and a possible slow dependency. A client uploading slowly may instead hit a client or HTTP request boundary. The measured phase matters more than a generic “raise all timeouts” response.

defaults
  mode http
  timeout connect 3s
  timeout client 30s
  timeout server 30s

backend checkout
  timeout queue 5s

These are illustrative values, not a recommended universal preset. Shorter values may protect finite connection capacity but can reject legitimate slow operations. Longer values can mask a deadlock and tie up resources. Coordinate HAProxy with upstream and downstream time budgets; otherwise one layer may give up while another keeps working. For long-lived streams or upgraded connections, inspect the relevant tunnel behavior instead of assuming the same HTTP idle settings fit.

Why can a healthy pool still produce failures?

A pool with two servers marked UP can still be overloaded. If maxconn or upstream capacity is saturated, requests queue. A short queue timeout can reject them while health probes continue to pass. A sticky-session policy can also send a disproportionate number of clients to one backend, so the aggregate pool looks underused while a particular node struggles. Check per-server sessions, queue depth, response-time distribution, and application resource metrics, not only UP/DOWN.

Partial failures deserve a controlled probe. Maybe /ready returns 200 while checkout fails because a downstream payment provider is unavailable. Maybe B has a stale certificate or a broken only-for-B configuration. Compare one failing request routed to B with the same request routed to A, while preserving authorization and request data. If the failure follows the request, the proxy may be innocent; if it follows the backend, inspect backend-specific config and logs.

A strong incident answer records timestamps and the chosen backend. Which client request failed? Which backend did HAProxy select? Did it queue, connect, send the request, and receive a response? Was that backend considered healthy at that instant? The answer narrows whether to change a check, a timeout, a server, or routing policy. Changing several settings at once destroys this evidence.

What does session persistence promise?

The HAProxy session-persistence guide describes approaches such as cookies and source-IP based persistence. The intent is repeated client traffic to the same backend. It is useful when server-local session state cannot yet be moved to shared storage, but it introduces coupling: a client may depend on a specific server remaining available. Persistence is a routing preference under its policy, not a guarantee that an unhealthy machine must continue serving.

For cookie persistence, explain who sets the cookie, what server identity it encodes, and whether the connection is HTTP so a cookie can be inspected. For source-IP persistence, discuss clients behind a NAT or proxy: many distinct users may share one apparent IP and concentrate on one backend. For a stick table, discuss the key, lifetime, memory capacity, and what happens on reload or across multiple HAProxy instances. The correct mechanism follows the client's identity and operational requirements; it is not interchangeable syntax.

Suppose a user's cookie points to B, but B goes down. The service must decide how a new backend is selected and what happens to B-local session data. Routing to A may restore connectivity but not restore a session stored only on B. A safer long-term application design often puts session state in a shared or otherwise recoverable store and treats affinity as an optimization. That is an architecture recommendation, not a claim that HAProxy copies application session data during failover.

How do retries interact with a write request?

The HAProxy retry and redispatch guide documents connection retries and routing behavior. An interview answer must distinguish a failed connection attempt from an application response and ask whether a request body was sent. A retry that is safe before a backend accepted a connection may be dangerous after a non-idempotent operation reached the application. Do not say that a proxy retry makes a payment exactly once.

For a POST that creates an order, the application should define an idempotency key or equivalent deduplication contract if retries can occur across client, proxy, and service layers. A timeout does not prove the operation failed; it proves the observer did not get a timely answer. If a sticky server goes down after receiving a write, redispatching to another server can create a duplicate unless the backend recognizes the operation. Explain where the durable operation identity lives and what response a repeat gets.

For a GET whose response is safe to repeat, the policy can be more permissive, but budget total latency and avoid a retry storm when every backend is failing. The proxy's retry configuration, the client's retry policy, and the service's semantics are separate; trace all three before changing HAProxy settings.

A practical diagnosis matrix

Use a four-column incident note: observation, likely boundary, confirming evidence, safe next action. If only B is DOWN, read its check results and backend logs before editing timeouts. If all backends are UP but queue time rises, inspect capacity and traffic distribution. If existing clients fail while new clients succeed, inspect persistence, old cookies, and drain behavior. If errors appear only on large uploads, inspect client/request timeout and body-handling limits. Each branch has a different hypothesis and an observation that could disprove it.

Do not equate a response status with one unique root cause. A proxy-generated error, a backend-generated error, and a client timeout can look similar from a browser. Use HAProxy logs, backend logs, timing fields, and server state around the same request ID. Then make one targeted change and measure whether the identified boundary improved.

Practice five linked questions

QuestionHAProxy connectionFollow-up to answer aloud
Design a Software Load BalancerHealth and capacity contractWhat removes a partially failed backend?
Debug a Round-Robin Load Balancer, Then Implement Consistent HashingDistribution and affinityWhich key keeps routing stable?
Debug and Improve a Load BalancerTrace a failed requestWas it queued, connecting, or waiting for a response?
Simulate sticky load balancer with shutdownFailed sticky targetWhere does a client go when its server is down?
Explain worker state machine load balancer designServer state transitionsWhat evidence moves a backend from down to up?

Start with Simulate sticky load balancer with shutdown. Name the affinity key, the health signal, and the fate of server-local session state when the selected node disappears. Then add a slow upstream and explain which timeout, if any, your trace would hit.

Sources and Further Reading