Back to path
IntermediateLinkly · Project 4 of 12 ~5h· 5 milestones

Spread load across a stateless app tier

Continues from the last build: a single app instance that caps throughput and can crash the service

Last rung, you put a cache in front of the database and reads stopped melting Postgres, but you only fixed half the picture.

Load balancing algorithmsStateless service designHealth checks (liveness/readiness)Session and counter externalizationHorizontal capacity planningHigh availability for load balancersConnection drainingAutoscaling triggers

What you'll build

A stateless app tier of interchangeable instances behind a load balancer, session and rate-limit state living in Redis instead of process memory, health checks pulling dead nodes out of rotation automatically, and the load balancer itself deployed as a redundant, multi-AZ front door so no single box, app or LB, can take the whole service down.

See how we teach, before you sign up

You don't just get code dumped on you. Every starter file and every solution is explained line-by-line, in plain English. Here's one real file from this project:

design/state-audit.mdmarkdown
# State Audit, Linkly App Tier

## Purpose
List every piece of state the current single app instance keeps in memory or on local disk, and where it moves once the tier is stateless.

## Inventory
- Session data (logged-in user, CSRF token): currently a Python dict in process memory -> move to Redis with TTL
- Rate-limit counters (requests per API key per minute): currently a local dict -> move to Redis INCR with expiry
- Short-code hot-key cache: already externalized in rung 3, no change needed here
- Ad-hoc local request logs written to disk: must ship off-box to the analytics pipeline, not solved in this rung

## Statelessness test
Kill any one instance mid-request. A client should see at most one retried request, never a lost session or a reset rate limit counter.

## Sign-off
- [ ] No client-affinity (sticky session) rule left enabled on the load balancer
- [ ] Every read of session/rate-limit state hits Redis, not a local variable
- [ ] A fresh instance boots with zero special state and can serve traffic immediately

Reading this file

  • Session data (logged-in user, CSRF token): currently a Python dict in process memory -> move to Redis with TTLSessions are the classic hidden state that breaks load balancing; they move to a shared, TTL-backed store.
  • Rate-limit counters (requests per API key per minute): currently a local dict -> move to Redis INCR with expiryRate limits must be shared across instances or a client can dodge the limit just by hitting a different box.
  • Kill any one instance mid-request. A client should see at most one retried request, never a lost session or a reset rate limit counter.This is the concrete, testable definition of stateless: any box can die without a user-visible correctness loss.
  • - [ ] No client-affinity (sticky session) rule left enabled on the load balancerSticky sessions are the most common way teams quietly reintroduce per-box state.

Audit every piece of state currently living on the single app instance before you can safely load-balance across many.

That's 1 of 8 explained code blocks in this single project.

The build, milestone by milestone

  1. 1

    Find every piece of state hiding on the box

    4 guided steps

    If any request has to land on the same server twice to work correctly, the load balancer cannot freely distribute load, which defeats the entire point of adding one.

  2. 2

    Choose the load-balancing algorithm and size the fleet

    4 guided steps

    The algorithm choice only matters once you know how uniform your request costs are; picking the wrong one either wastes complexity or leaves some instances hot while others idle.

  3. 3

    Stop the load balancer from becoming the next single point of failure

    4 guided steps

    You just removed one single point of failure and quietly created another one hop upstream; a load balancer with no redundancy and no health checks is still a single box that can take Linkly down.

  4. 4

    Size the fleet with real capacity math

    4 guided steps

    A design that says 'add more instances' without a number is not a capacity plan; the number is what makes the design defensible and tells you when to actually scale out.

  5. 5

    Write the ADR and update the architecture diagram

    4 guided steps

    A design is only as useful as the record of why it was made; the next engineer, or an interviewer, needs the reasoning, not just the final diagram.

What's inside when you start

3 starter files, ready to clone
5 guided milestones
5 full reference solutions
8 code blocks explained line-by-line
5 "is it working?" checks
4 interview questions it prepares you for

You'll walk away with

ADR-004: Stateless App Tier Behind a Load Balancer, with context, options, decision, and consequences
Updated architecture diagram showing the load-balanced, health-checked app tier and where session state now lives
A capacity worksheet showing peak QPS, per-instance capacity, and the resulting instance count with N+1 redundancy
A state audit listing every piece of app-tier state and where it moved

This is portfolio-grade. Build it free.

Sign up to unlock every milestone step-by-step, the code skeletons, full reference solutions, and checkable tasks, with your progress saved as you build.

Start building