Serverless and edge functions
Functions scale per request; the database they call does not.
Predict first
Before you read: predict
ExamHall builds result PDFs in a Lambda function. Its module-scope code, outside the handler, opens one Postgres connection, which later invocations in the same environment reuse. On this lesson's Lambda model, a frozen environment is kept and reused by the next request. No environment of the function exists before 09:00:00. At 09:00:00 six result-PDF requests arrive at once; each handler runs for 2 seconds. At 09:00:10 six more arrive at once.
How many Postgres connections has the function opened by 09:00:11?
The 30-second version
Lambda gives each concurrent request its own environment and bills only running time. A new environment runs Init, module-scope code included: the cold start. Finished environments freeze and are reused, connections and all, but never shared. Each environment's own Postgres connections count against one limit: put a pooler or HTTP driver between.
Functions scale per request; the database they call does not.
How it works
Step 1 of 11
In the kitchen
- one more hawker goes out for every section calling for drinks at once → one environment per concurrent request (step 1)
Analogy: Hawkers selling drinks in a stadium's stands
| In the stands | In serverless |
|---|---|
| one more hawker goes out for every section calling for drinks at once | one environment per concurrent request (step 1) |
| hawkers are paid per tray sold, not for standing by | billed while code runs (step 5) |
| a new hawker first collects an apron, a tray and a float at the commissary | Init: the cold start (step 3) |
| one back from a round goes straight out again | freeze and reuse (step 4) |
| no hawker remembers which seats ordered | statelessness (step 7) |
| every round ends at the half-time whistle | the timeout (step 6) |
| each new hawker takes one of the bar's eight taps and keeps it; the ninth is turned away | connections per environment, refused past the limit (steps 9, 10) |
| a bar team pours through the eight taps for every hawker | a pooler (step 11) |
In real terms: concurrency is set by traffic, not by you; the connection count follows it unless something in between caps it.
Breaks down when: a hawker can see the bar's queue and wait, while a function opens its connection at Init without looking.
Contrasting case: a long-running container keeps one pool for many requests and its own count of instances, so its connection total is replicas × pool size and changes only when you scale it (sd-horizontal-scaling-lb).
Examples, run for real
4.1 ExamHall EXH-4000 → MR !4300: the exam-end burst
At 09:00 an exam closed and result-PDF requests reached ExamHall's function one after another, each still running when the next came, so Lambda added one environment per request. Each environment's module-scope code opened its own Postgres connection; once the server's 27 slots for ordinary roles were taken, every further environment failed Init with SQLSTATE 53300 (EXH-4000). MR !4300 routes the function through a pooler that holds ten database connections; Postgres then sees ten, and nothing is refused.
4.1 postgres 17.11 · max_connections 30 · superuser_reserved_connections 3 · reserved_connections 0
4.1 EXH-4000: 40 environments open one connection each at Init: connected 27 (client backends in the container 27) · refused with 53300 13 ("remaining connection slots are reserved for roles with the SUPERUSER attribute")
4.1 MR !4300: the same 40 environments through the pooler (max 10): examhall_pdf backends while all 10 are lent 10 · refused with 53300 0
4.2 Proof domain, media streaming: a premiere's token checks
A streaming premiere sends 2,000 token checks a second; each check runs 100 ms and Init takes 300 ms. The function's module scope opens a pool of 1.
4.2 2000 checks/s x 100 ms, Init 300 ms: busy environments at steady state 200 (formula 200) · environments created 800 (ramp-up 2000/s x 400 ms = 800) · pool 1 each -> 800 connections open from this function
examples: 4.2 asserted (4.1: practice-p1-p2.mjs)
Once the load is steady, 2,000 × 0.1 = 200 environments are busy at once (step 2). In the first moments each new environment is busy for Init plus the check, so 800 were made, and each frozen one keeps its connection: the database sees 800 from this one function until Lambda shuts the idle environments down (steps 4, 9).
Try it
Answer first, then check. Nothing is saved.
Question 1 of 6
At 10:00 a mock exam closes. From 10:00:00 a result-PDF request reaches ExamHall's Lambda function every 100 ms, 48 in all, and each runs for 30 seconds, so all 48 are still running when the last arrives. The function runs on this lesson's Lambda environment model, and no environment was running before. Each environment's module-scope code fills a pool of 2 Postgres connections at Init, opening them one after the other as the role examhall_pdf, which is not a superuser and has no other role granted; if either is refused, Init fails and closes what it opened. Postgres runs with max_connections = 50, the default superuser_reserved_connections = 3, reserved_connections = 5 and nothing else connected.
How many of the 48 environments fail their Init with SQLSTATE 53300?
Question 2 of 6
A pooler goes between the same function and the same Postgres, on this lesson's pooler model: each environment's module-scope pool of 2 now connects to the pooler, which holds at most 12 connections to Postgres and lends them to the environments' transactions. The same 48 requests arrive the same way, and each runs one transaction that is still open when the last request arrives.
At that moment, how many requests wait in the pooler's queue, and how many connections does Postgres refuse?
Question 3 of 6
ExamHall's exam-code check runs as a Cloudflare Worker. It keeps let checks = 0 at module scope; each request runs checks += 1 and returns checks. Three requests arrive at the same moment.
On this lesson's Workers model, how many different sets of values can the three requests return, whichever request gets which?
Question 4 of 6
In a design round you put ExamHall's result PDFs on Lambda, one invocation per candidate; the round runs on this lesson's Lambda environment model. The interviewer then asks how your design builds a whole cohort's merged PDF, which takes 40 minutes of work in one run.
Which answer survives the next question?
Question 5 of 6
ExamHall's exam-code check runs on Lambda. To slow guessing, its module-scope code keeps a Map of wrong codes per candidate, and the handler refuses a candidate's sixth wrong code and every one after it. On this lesson's Lambda model, a frozen environment is kept and reused by the next request. No environment is running; Init takes 300 ms and each invocation 200 ms. One candidate's wrong codes arrive one at a time at 09:00:00, 09:00:01, 09:00:02 and 09:00:03; at 09:00:04 four arrive at once, and at 09:00:05 four more arrive at once.
How many of the 12 does the function refuse?
Question 6 of 6
A media-streaming service makes thumbnails, 2 s of work each, spread evenly over the day. Choice 1: a function with 1 GB of memory, at scenario prices of $0.0000167 per GB-second of duration and $0.20 per million requests. Choice 2: containers at $0.04 per hour each, running all day, each making one thumbnail at a time.
Which choice costs less per day at 1,000 thumbnails a day, at 50,000 and at 200,000?
Go deeper
Pro tip
- When the interviewer says "serverless scales", answer with the number that fails: concurrency × connections per environment, against
max_connections; then name the pooler or HTTP driver that caps it. When: "Your functions scaled to 800 concurrent instances and Postgres fell over. Why?" Status: SELF; not run.
Source
Valid as of 2026-10-13.
- AWS Lambda, Lambda execution environment lifecycle (named in the row): https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtime-environment.html ·
aws-lambda-lifecycle.txt. "In the Init phase, Lambda performs three tasks"; "The Init phase is limited to 10 seconds."; "When the function is invoked again, Lambda thaws the environment for reuse."; "if your Lambda function establishes a database connection, instead of reestablishing the connection, the original connection is used in subsequent invocations." Steps 3, 4, 6. - AWS Lambda, Understanding Lambda function scaling (concurrency): https://docs.aws.amazon.com/lambda/latest/dg/lambda-concurrency.html ·
aws-lambda-concurrency.txt. "For each concurrent request, Lambda provisions a separate instance of your execution environment."; "Concurrency = (average requests per second) * (average request duration in seconds)"; "a total concurrency limit of 1,000 concurrent executions across all Event Functions in an AWS Region". Steps 1, 2. - AWS Lambda quotas: https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html ·
aws-lambda-quotas.txt. "900 seconds (15 minutes)". Step 6. - AWS Lambda pricing: https://aws.amazon.com/lambda/pricing/ ·
aws-lambda-pricing.txt. "Duration is calculated from the time your code begins executing until it returns or otherwise terminates, rounded up to the nearest 1ms". Step 5. - Cloudflare Workers, How Workers works (named in the row): https://developers.cloudflare.com/workers/reference/how-workers-works/ ·
cf-how-workers-works.txt. "a single Workers instance may handle multiple requests including concurrent requests in a single-threaded event loop"; "there is no guarantee that any two user requests will be routed to the same or a different instance of your Worker". Step 8. - Amazon RDS Proxy (named in the row): https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html ·
aws-rds-proxy.txt. "RDS Proxy establishes a database connection pool and reuses connections in this pool."; "RDS Proxy queues or throttles application connections that can't be served immediately from the connection pool." Step 11. - PostgreSQL 17, Connection settings and Error codes: https://www.postgresql.org/docs/17/runtime-config-connection.html ·
pg17-runtime-config-connection.txt; https://www.postgresql.org/docs/17/errcodes-appendix.html ·pg17-errcodes.txt.superuser_reserved_connections: "Whenever the number of active concurrent connections is at least max_connections minus superuser_reserved_connections, new connections will be accepted only for superusers."; "The default value is three connections.";reserved_connections: "Determines the number of connection “slots” that are reserved for connections by roles with privileges of the pg_use_reserved_connections role."; 53300too_many_connections. Step 10 (withdb-connection-poolingstep 8).
Related lessons
Checked against the tools and docs as of 2026-10-13.