Module F-10·20 min read

What each abstraction takes away — cold starts, execution ceilings, no work after the response returns, ephemeral disk, and why an edge runtime cannot hold a WebSocket or a TCP pool.

JJS
Written by Jatin Jain Saraf · Senior Software Engineer

Module F-10 — Compute Models: VMs, Containers, Serverless, and the Edge

What this module covers: Each step up the compute abstraction ladder hands you something and quietly takes something away, and the things taken away are what cause the outages. This module covers VMs, containers, serverless containers, functions, and edge runtimes — with a specific inventory of what each one removes: cold starts, execution-time and memory ceilings, the rule that no work happens after the response returns, ephemeral local disk, and the inability of an edge runtime to hold a WebSocket or a database connection pool. It ends with the constraint that decides more architectures than any other: where the code runs relative to where the data lives.


The Ladder, and the Trade at Each Rung

UnitStart-upYou manageScales to zeroHolds state between requests
Bare metalMachineMinutesEverythingNoYes
VMGuest OS30s–2minOS, runtime, appNoYes
ContainerProcess + namespaces1–10sImage, appRarelyWithin the container's life
Serverless containerContainer, managed1–10s coldImage, appYesOnly while an instance is warm
Function (FaaS)Handler invocation50ms–2s coldApp codeYesUnreliably
Edge runtimeV8 isolate~0–5msApp codeYesNo

Read the last two columns together. As start-up time and operational burden go down, the ability to hold anything goes down with them — and "anything" includes connections, caches, sockets, timers, and in-flight background work. That's not incidental; it's the mechanism. A platform can only start you in five milliseconds and scale you to zero if it's free to discard you at any moment.

Analogy: the ladder runs from owning a house, to renting a flat, to a hotel room, to a hot-desk, to a phone booth. Each step is cheaper, faster to get into, and less of your responsibility. Each step also gives you less room to leave anything lying around — and by the phone booth, you can't even keep a phone line open between calls.

Why this matters in production: every one of these platforms runs a "hello world" identically well. The differences only appear when your code wants to keep a database connection, do work after responding, write a temp file, or hold a socket open. Those are precisely the things a real application does, and discovering the constraint after committing to the platform is the expensive path.


VMs and Containers: The Familiar End

Virtual machines give you a full guest OS with its own kernel. Strong isolation, any workload, complete control — and you own patching, configuration drift, and multi-minute boot times. Autoscaling on a two-minute boot means you're always reacting late.

Containers share the host kernel and isolate with namespaces and cgroups. Start-up drops to seconds, images are immutable and reproducible, and density goes up substantially. Two properties matter for design:

  • The filesystem is ephemeral. Anything written inside a container disappears on restart unless it's on a mounted volume. This is the same "local files are state" problem as Module F-9, now enforced by the platform.
  • Resource limits are enforced by cgroups, and runtimes often don't notice. A JVM or Node process that reads the host's memory rather than its cgroup limit will happily grow past the container's ceiling and be OOM-killed — a restart loop with no application error to explain it.

Containers keep the crucial property the higher rungs give up: a container is a long-running process. It can hold a connection pool, an in-memory cache, a WebSocket, a background timer. Everything below this line loses some of that.


Functions: Four Constraints That Reshape Designs

FaaS (AWS Lambda, Vercel Functions, Cloud Functions) runs a handler per request and charges per invocation-millisecond. The operational win is real — no servers, scale to zero, scale to thousands. Four constraints come with it.

1. Cold starts

When no warm instance exists, the platform provisions one: fetch the code, initialise the runtime, run module-level code, then invoke the handler. Roughly:

Runtime / situationTypical cold start
Node.js / Python, small bundle100–400 ms
Node.js with a large dependency tree500 ms – 2 s
JVM / .NET1–5 s
Inside a VPC (historically)+seconds
Edge / V8 isolate~0–5 ms

Cold starts are a tail-latency phenomenon by construction (Module F-4). Your p50 can be excellent while p99 includes a full initialisation. And the shape is spiky: a traffic surge triggers many simultaneous cold starts precisely when latency matters most.

What actually helps: smaller bundles and fewer dependencies (the single biggest lever), moving expensive setup out of the hot path, provisioned concurrency where the platform offers it — with the cost named, since provisioned concurrency is paying for idle capacity, which is most of what serverless promised to eliminate.

2. No work after the response returns

This is the constraint that breaks the most existing code. In a long-running server, this is idiomatic:

typescript

On FaaS the execution environment may be frozen or destroyed the moment the response is returned. Those three background tasks might complete, might partially complete, or might never start — and it varies invocation to invocation, so it "works in staging" and drops a fraction of emails in production. Silent, partial, non-deterministic data loss is the worst failure category to debug.

The fix is architectural, not a workaround: anything that must happen goes onto a durable queue before you respond.

typescript

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.