The challenge
Bloom Learning provides online curriculum and assessments to schools across South Africa and Kenya. Demand had grown tenfold in three years, and the platform had not. Built quickly in the early days, it ran on two overworked servers and slowed to a crawl above 6,000 concurrent users. At 9,000 it fell over.
The failures always came at the worst moment, because load peaks when schools schedule assessments in the same week. Two provincial exam windows in a row saw outages, learners lost half-written answers, and two large school groups gave notice. Growth had become the thing threatening the business.
Bloom needed the platform rebuilt for scale without pausing a live service that schools depended on every weekday.
The approach
A big-bang rewrite was off the table: the platform could not go dark for a term. Instead we rebuilt it in slices, moving one subsystem at a time onto new infrastructure while the old system kept serving. Assessments moved first, because that is where failure hurt most, and every migration was rehearsed against replayed production traffic before real learners touched it.
- Load-tested the existing system to find the true breaking points before changing anything
- Migrated subsystem by subsystem, assessments first, with the old platform still serving
- Replayed recorded production traffic against each new slice before cutover
- Moved to autoscaling on Kubernetes so exam-week capacity does not run all year
- Set an explicit target with Bloom: 50,000 concurrent learners with response times under 300 milliseconds
What we built
The rebuilt platform is a Django application decomposed into independently scaling services on Kubernetes, with PostgreSQL read replicas, Redis caching, and content served from edge locations close to learners. Assessments got special treatment: answers save continuously in the background, so a dropped connection on township Wi-Fi costs a learner seconds, not an essay.
- Independently scaling services for assessments, content, and reporting workloads
- Continuous answer autosave, so no learner loses work to a connection drop
- Autoscaling that grows from baseline to exam-week capacity in minutes and back down after
- Content delivery from edge locations, cutting video start times for rural schools
- Read replicas and caching that took the primary database from 95% to 30% load
- Load-test rehearsals baked into the release process before every exam season
9,000
concurrent users where the old platform failed
52,000
concurrent users sustained in load rehearsal
280ms
p95 response time at peak
The outcome
The platform now serves 120,000 active learners and has run three consecutive exam seasons without an outage, including a November morning where 40,000 learners wrote assessments concurrently. The two school groups that gave notice stayed after watching a season run clean, and Bloom has since signed its largest contract, a 30,000-learner provincial programme it previously could not bid for.
Cost moved in the right direction too. Because capacity now scales with actual demand instead of running at exam-week size all year, infrastructure cost per learner fell 64% even as learner numbers tripled. Bloom’s own developers ship to the new platform daily, and the load rehearsal before each exam season has become a routine rather than a rescue.




