Module 01 · Lesson 2 of 14Free
Request lifecycle: what happens when you open a website
- Level
- Beginner
- Topic
- System design fundamentals
- Reading time
- 15 min
When you finish this page you can
- Trace a product-page request from a phone through the network, application and database.
- Explain why server response time differs from the time before a page becomes visible.
- Identify which work caching and connection reuse can skip.
- Locate a likely failure from the last successful step.
Builds on 1 lesson
Start with lesson 113 minVideo lesson · coming soon
Asha opens a product page on from her phone. In this lesson’s example, the application takes 95 ms, but the product text appears after 400 ms.
Where did the rest of that time go? We’ll follow one request from the address bar to the screen.
Kartly records no application request when Asha sees an error. Does that prove her phone never contacted Kartly?Show answer
Diagram not drawn yet: request-lifecycle-kartly.svg
The phone first asks DNS for Kartly’s address. It then establishes TCP and TLS with the public entry point, which forwards HTTP to one app server. The app reads PostgreSQL and calls the pricing service. The response returns through the entry point to the phone, where the browser renders it.
Kartly is still at its one-server stage: one app server with eight CPU cores and one PostgreSQL database. The public entry point below is a forwarding role, not a second app server.
We’ll trace over . Other transports come later; first, we need a clear path to follow.
Find the address before connecting
Asha enters https://kartly.example/products/482.
For our request, https selects secure communication. kartly.example identifies the host. /products/482 identifies the product resource.
, the Domain Name System, finds an IP address for the hostname. A cached answer can avoid a remote lookup. Otherwise, the browser’s lookup reaches a DNS resolver, a service that obtains the answer. DNS resolves the hostname, not the product path.1
Assume Kartly’s answer is 203.0.113.10. This documentation address represents its public entry point, not its database.
Our scenario assigns 40 ms to the lookup. That is an illustrative duration, not a normal value for every phone.
Notice the boundary: knowing an address does not prove anything is listening there. If someone gives you a building’s address, the building can still be closed.
Asha now knows where to connect. She has not requested the product yet.
Establish a protected conversation
TCP establishes a connection through three messages: SYN, SYN-ACK and ACK. then authenticates the server and establishes before the request. These are connection setup steps, not product-page work.1
Think of the different questions they answer:
- DNS: where should the phone connect?
- TCP: can these establish a connection?
- TLS: can the phone establish a protected conversation with the intended server?
For this scenario, assign 60 ms to TCP setup. Assign another 60 ms to TLS setup. These are budget assumptions, not universal handshake timings.
Suppose the public entry point is reachable, but its is invalid. Our expected outcome is a browser security warning. Making the product query faster would not help: application code has not run.
We choose to stop at that warning rather than bypass verification. A product page that loads through an untrusted connection would defeat the protection HTTPS is meant to provide.
Connection setup is now complete. Only now does the browser ask for the product.
The request reaches application code
HTTP carries the request and response. Here is a readable HTTP/1.1 example; headers carry information about the message, and the path identifies the requested resource.1
GET /products/482 HTTP/1.1
Host: kartly.example
Accept: text/htmlAt Kartly’s public entry point, a forwards requests to the application. A uses this forwarding role to distribute requests across available app servers. NGINX supports forwarding to a single destination or a server group.2
Kartly currently has only one app server, so there is no distribution choice. For our example, the entry point also handles the phone’s TLS connection.
The distinction matters: the phone’s connection ends at the entry point. Forwarding to the app is another network hop. Encryption on that internal hop is a separate configuration choice.
Here is the request lifecycle inside this scenario:
- The entry point forwards the product request to the app.
- The app selects the handler for
/products/482. - The handler asks PostgreSQL for product 482.
- PostgreSQL returns the stored product fields.
- The app asks the pricing service for the current price.
- The app combines those results into HTML.
- The entry point forwards the response to the phone.
The pricing service is an existing dependency in Kartly’s example world. We are not introducing a new service to solve this request.
Each component has a boundary
This is the responsibility map for our design:
| Component | Responsibility | Talks to | State it keeps | Failure consequence |
|---|---|---|---|---|
| Phone browser | Request and display the page | DNS, entry point | Cached data, connections | Error or incomplete screen |
| DNS resolver | Obtain the hostname’s address | DNS servers | Cached answers | No usable destination |
| Public entry point | Accept and forward HTTP | Phone, app | Connections, routing configuration | App may receive nothing |
| App server | Assemble the product page | Database, pricing service | Current request data | Page cannot be assembled |
| PostgreSQL | Store product records | App | Persistent product data | Product lookup fails |
| Pricing service | Supply the current price | App | Pricing data | Current price is unavailable |
This page is a read path. Opening it does not create an order or change stock. That keeps a failed page load separate from a failed purchase.
The server has assembled a response, but the customer still needs something visible.
A response is not a screen
Our application returns HTML through the entry point:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
<!doctype html>
<html lang="en">
<head><title>Desk lamp</title></head>
<body><h1>Desk lamp</h1><p>₹799</p></body>
</html>turns downloaded content into visible pixels. The browser parses HTML, applies styles, calculates positions and paints. Images, stylesheets and scripts can require further requests; parsing can begin before the complete HTML arrives.1
For our calculation, the small HTML response contains everything needed to show the initial product text. A product photograph can appear later. This assumption keeps “text visible” separate from “every resource finished”.
Imagine two versions of Kartly:
- Version A returns the product text in HTML.
- Version B returns an empty page, then requires JavaScript to fetch the product.
In version B, our product fetch becomes another dependency before text can appear. That may suit an application with complex client-side behaviour, but it adds work to this particular path.
A successful HTML response therefore proves less than a successful customer experience. We need to account for the whole path.
Account for the missing milliseconds
These numbers are an illustrative budget for Asha’s first visit. They are not measured production statistics.
| Stage | Added time |
|---|---|
| DNS lookup | 40 ms |
| TCP setup | 60 ms |
| TLS setup | 60 ms |
| HTTP request travels to entry point | 30 ms |
| Entry-point forwarding overhead | 1 ms |
| Application, including dependencies | 95 ms |
| First response bytes travel back | 30 ms |
| Remaining HTML transfer | 24 ms |
| Initial text rendering allowance | 60 ms |
The application’s 95 ms follows Kartly’s established example: 5 ms of CPU work, 40 ms waiting for PostgreSQL and 50 ms waiting for pricing.
Do not add those dependency waits again. They are already inside application time.
Reach the first response byte
40 + 60 + 60 + 30 + 1 + 95 + 30 = 316 ms
The application contributes only part of the wait. Connection setup and travel happen outside its timing.
Finish receiving the HTML
316 ms + 24 ms = 340 ms
Receiving the first byte and receiving the complete document are different milestones.
Show the initial product text
340 ms + 60 ms = 400 ms
This simplified budget places rendering afterward. Actual parsing and downloading can overlap, so this is not a browser scheduling formula.
Now suppose you halve application time. Under these assumptions, you save about 48 ms—not half the page-load time.
That calculation tells you where further investigation belongs. It also raises another question: must every visit pay every cost?
The next request can skip work
Caching means retaining a result for reuse. Connection reuse means retaining the conversation itself. They save different work: a cached address avoids lookup, while an existing connection avoids setup. curl also reuses connections across transfers within one invocation.1
Diagram not drawn yet: request-lifecycle-reuse.svg
Two panels compare a fresh connection with an existing connection. The fresh path performs DNS, TCP and TLS before HTTP. The existing-connection path sends a new HTTP request without those setup steps. Both still reach the app for an uncached product response.
For our second request, assume the connection is still usable. Keep every other budget item unchanged.
That removes 160 ms of setup from the example. Initial text would appear after 240 ms. The product still comes from the application.
A different optimization is to reuse a stored response. For Kartly, that creates a product question: how old may the displayed price be?
How should Kartly reduce repeat-visit delay without accidentally treating an old price as current?
Always establish a fresh connection.
Each request repeats setup. In our budget, that adds 160 ms without making the product data fresher.
Reuse the complete product response without checking its age.
A stored product page avoids more work, but our customer may see yesterday’s price unless reuse has an explicit freshness policy.
Reuse connections first; give response caching its own freshness rules.
The next request avoids connection setup but still asks the app for current product information. Cache stable assets separately.
Why this choice
The simplest improvement for this scenario avoids repeating setup without changing where the price comes from.
Response caching saves more work, but it answers a different question: when is old content acceptable? A static help page and a changing price need different policies.
Our choice changes if the product team accepts a bounded delay in displayed prices. Then cached product responses become an option. Checkout must still validate the purchase price.
Connection reuse also has a limit: if the connection closes, the next request must establish another one. It is an opportunity, not a guarantee.
Cache placement develops response caching. For now, keep the two questions separate: “Can we reuse the connection?” and “Can we reuse the answer?”
Find the last successful boundary
Use the following as a diagnosis exercise for our design. Symptoms are possible outcomes, not exact browser messages or universal status-code mappings.
| Failure | What Asha may see | Evidence to seek | Recovery action |
|---|---|---|---|
| DNS lookup fails | Site cannot be found | Lookup result; no connection attempt | Restore the DNS answer or resolver access |
| TCP cannot connect | Loading, then connection error | Connection failure; no HTTP request | Restore routing or the listener |
| TLS verification fails | Security warning | Certificate verification error | Repair certificate configuration |
| Entry point cannot reach app | Gateway error | Forwarding error in entry-point logs | Restore the app or its route |
| App handler fails | Error page | App error for this request | Fix or roll back the failing change |
| Database or pricing call fails | Error page, or missing price if designed | Dependency error and duration | Restore the dependency; show an explicit unavailable state |
| Response transfer breaks | Partial page or network error | Bytes sent versus received | Investigate the connection interruption |
| Rendering or script work fails | Incomplete or unresponsive page | Browser errors and performance recording | Fix the client resource or code |
A proxy can enforce connection and read timeouts. NGINX documents these separately; its read timeout measures gaps between reads, not a total .2
For Kartly, choose an explicit failure response when current pricing is unavailable. Do not silently invent a price. A message such as “Price temporarily unavailable” lets Asha distinguish missing information from an actual offer.
The useful investigation question is not “Did the website fail?” It is “What was the last completed step?”
Try it yourself
Run this against a public example site, not Kartly’s fictional domain. In Windows PowerShell, use curl.exe instead of curl.
curl --http1.1 -sS -o timing-page.html -w "dns=%{time_namelookup} tcp=%{time_connect} tls=%{time_appconnect} first=%{time_starttransfer} total=%{time_total}\n" https://example.com/Illustrative output:
dns=0.040 tcp=0.100 tls=0.160 first=0.316 total=0.340These are cumulative seconds from the start. Subtract adjacent values: TCP adds 60 ms here. The interval after TLS includes request travel, server work and response travel—not server work alone. curl downloads the response but does not render a browser page.3
Your results will differ. A configured proxy can also change what the connection timings represent.
Where this shows up
- Design: a URL shortener on a single server: separates request handling from the stored lookup.
- Design: a fast product catalog page: decides which answers can avoid the original .
One request is now accounted for; next, Server concurrency explains what happens when many arrive together.
Common mistakes
- Timing only the handler. Our 95 ms measurement excludes setup, travel and rendering.
- Treating DNS as a product lookup. Its answer gets the phone to an entry point, not to a database row.
- Treating reuse as freshness. An existing connection says nothing about whether a stored price is current.
- Adding nested times twice. Database time is already included when the application measurement surrounds that call.
Check your understanding
Asha receives a certificate warning. Should you start by inspecting the product query?Show answer
The next product request uses the existing connection but has no cached response. Does it skip PostgreSQL?Show answer
curl reports first=0.500 and total=0.700. Did the server spend 500 ms executing the handler?Show answer
Kartly logs a successful HTML response, but Asha’s product image never appears. Can both observations be correct?Show answer
Summary
- A page appears after address lookup, connection setup, HTTP handling, response transfer and browser rendering.
- DNS finds an address; TCP establishes a connection; TLS protects it before HTTP carries the request.
- The entry point forwards to the app, which gathers product and pricing data before returning HTML.
- Cached answers and reused connections skip different work. Neither automatically guarantees a current price.
- Diagnose failures by finding the last successful boundary, and distinguish application time from the complete customer experience.