Back to BlogIndustry Guides

Surviving a Flash Sale: Building for the Traffic Spike

Rupak Amin

Founder & Lead Engineer, RAITHub

10 min read

RAITHub ships and tests production software. See QA as a Service or talk to us.

A flash sale breaks a store two ways: a read spike that overwhelms the database as everyone loads the same product, and a write spike that oversells limited stock as everyone checks out at once. Survive both by caching the hot read path, reserving stock atomically inside the order transaction, protecting checkout with a queue and rate limits, and load-testing to the expected peak before the sale.

If you would rather have it built and tested for you, see how RAITHub would build this below.

Why does a store fall over during a flash sale?

Because normal traffic and a flash sale are different shapes of load. Normal traffic is spread out; a flash sale is thousands of people doing the same thing in the same minute. The read side (everyone loading the deal page) and the write side (everyone checking out) each hit a different limit, and most stores have never tested either at that scale. A sale is the worst time to discover which one gives way first.

FailureWhat happensThe fix
Read spikeEvery page view hits the database for the same product; connections run outCache the product and listing pages at the edge; serve stock separately
OversellTwo buyers pass the stock check before either write lands; you sell the last unit twiceDecrement stock inside the order transaction with a row lock
Checkout stampedeThousands of writes arrive at once; the database queues and times outA waiting-room queue and per-user rate limits in front of checkout
Payment webhook floodRetries and duplicates arrive out of order during the peakIdempotent, applied-exactly-once webhook handling

How do you stop overselling when everyone buys at once?

Never check stock and then write the order in two steps. Between the check and the write, another request can slip through, so you sell the last unit twice. Decrement stock inside the same database transaction as the order, with a row lock, so the second buyer waits and then sees zero. This is the single most important flash-sale fix, and it is the same discipline that keeps a gift-card balance exact, covered in preventing overselling with a reservation inside the order transaction.

BEGIN;
-- Lock the stock row; a concurrent buyer waits here instead of racing.
UPDATE product_variants
SET stock = stock - $2
WHERE id = $1 AND stock >= $2
RETURNING stock;
-- If no row is returned, stock was insufficient: abort and tell the buyer.
INSERT INTO orders (...) VALUES (...);
COMMIT;

The WHERE stock >= $2 guard means the update only succeeds when there is enough stock, so the database itself refuses to oversell. No application-level check can match that guarantee under concurrency.

How do you protect the database from the read spike?

Keep the deal page off the database for most visitors. The product name, images, price and description change rarely during a sale, so cache the rendered page or its data at the edge or in a cache layer, and serve it to everyone without a database round-trip. Serve the fast-changing part (is it in stock, how many left) from a small, cheap read, or show a coarse signal ("selling fast") rather than an exact count. The goal is that a browsing visitor who never buys costs you almost nothing.

  • Cache the hot pages with a short time-to-live, and purge on price or stock-status change.
  • Separate "the product" from "the stock." Product data is cacheable; the live count is not, so do not let the live count drag the whole page onto the database.
  • Rate-limit aggressively. Bots and refresh-hammering are a large share of flash-sale load; a rate limit that works without extra infrastructure is covered in the engineering notes on this site.

Do you need a waiting-room queue?

For a genuinely large spike against limited stock, yes. A waiting room admits buyers to checkout at a rate the database can actually handle, instead of letting everyone hit it at once. Each buyer gets a place in line and a short, fair window to complete payment; if they do not, their reserved stock is released. This turns a stampede into a steady stream, and it is kinder to buyers than a store that simply errors. For a smaller sale, per-user rate limits and the atomic stock guard are usually enough.

How do you keep payments correct under the peak?

Payment webhooks arrive retried, duplicated and out of order at the worst moment. Treat every money event as applied-exactly-once: a stable key, a recorded result, and a safe no-op on a repeat. The reasoning and the tests are in testing payments and webhooks end to end. A webhook that is processed twice during a flash sale is how a store double-charges hundreds of buyers in a minute.

How do you prove it will hold before the sale?

Load-test to the number you actually expect, on infrastructure like production, before the sale, not during it. A load test that drives the real checkout path, including the stock decrement and the payment webhook, finds the limit you will hit for real.

// k6: ramp to the expected peak and drive the real checkout path.
import http from 'k6/http'
import { check } from 'k6'

export const options = {
  stages: [
    { duration: '1m', target: 200 },    // warm up
    { duration: '2m', target: 2000 },   // the expected peak
    { duration: '1m', target: 0 },      // ramp down
  ],
  thresholds: { http_req_duration: ['p(95)<800'] },  // p95 under 800ms
}

export default function () {
  const res = http.post('https://staging.example.com/api/checkout', payload())
  check(res, { 'not oversold': (r) => r.status !== 409 || r.json('reason') === 'sold_out' })
}

Run it against staging, watch the database connections and p95 latency, and fix the first thing that breaks. Then run it again. A sale you have load-tested to peak is a sale you can forecast; one you have not is a gamble.

Buy, build or hire?

OptionChoose this whenThe catch
A hosted platform's sale tooling (Shopify and similar)A standard store within the platform's limits, with its payment methodsYou inherit its scaling and its oversell behaviour; custom stock rules and local gateways may not fit
Just adding more serversYou have headroom and the bottleneck is CPU, not the database or stock logicMore servers do not fix oversell or a single hot database row; they can make write contention worse
Custom build and hardeningLimited stock, local payment gateways, or a spike far above normal trafficYou own the caching, the atomic stock path and the load tests that prove it

How long does it take to build yourself, and what is the risk?

For an experienced team hardening an existing store (atomic stock, caching the hot path, a queue and load tests), our estimate is 2 to 4 weeks. The main risk is testing on the wrong shape of load: a store that handles steady traffic can still collapse in the first minute of a sale, because the failure is concurrency on a few hot rows, not total throughput. Load-test the real checkout path at the real peak, or you have not tested the thing that breaks.

Why RAITHub for this

  • Oversell prevention in production. TheSkinProof, the founder's own venture built and run by RAITHub, decrements per-variant stock inside the order transaction, with 750+ tests.
  • Load and performance testing. QA as a Service includes k6 load tests and performance budgets gated in CI, so the limit is known before the sale.
  • Idempotent payments. Money events are handled applied-exactly-once, which is what keeps a flash sale from double-charging under webhook retries.

When you don't need us

  • Your platform's limits cover you. A modest sale within a hosted platform's scaling may need no custom work.
  • Your stock is effectively unlimited. No oversell risk removes the hardest part of a flash sale.
  • You only need the load test. A one-off pre-sale load and QA audit may be enough on its own.

How RAITHub would build this

  • Hot-path caching: product and listing pages cached, live stock served cheaply and separately.
  • Atomic stock: stock decremented inside the order transaction with a row lock, so the database cannot oversell.
  • Checkout protection: a waiting-room queue for large spikes, per-user rate limits, and idempotent payment webhooks.
  • Load testing: k6 ramps to the expected peak against staging, with p95 and database-connection budgets, gated in CI.

Timeline: hardening an existing store is typically 2 to 4 weeks as a focused rescue; inside a new store MVP the sale path fits the 4 to 6 week fixed-scope range. See SaaS development, QA as a Service and the ecommerce industry page. A related build is multi-warehouse inventory and fulfilment logic.

You receive: the caching and stock changes, load-test scripts and CI performance budgets, handover docs, and full IP in your name under NDA.

Next step: book the free 15-minute technical audit with your expected peak and stock figures, and we will follow up with a written fixed quote.

Frequently asked questions

Why does my store slow down or crash during a flash sale?

Because a flash sale is thousands of people doing the same thing at once, which hits two limits a normal day never reaches: a read spike on the deal page and a write spike at checkout. Cache the reads, make the checkout write atomic, and load-test both to the expected peak.

How do I stop overselling during a flash sale?

Decrement stock inside the same database transaction as the order, with a row lock and a WHERE stock >= quantity guard, so the database itself refuses to oversell. Checking stock and then writing the order in two steps always races under flash-sale concurrency.

Do I need a waiting-room queue for a flash sale?

For a large spike against limited stock, yes: a queue admits buyers at a rate the database can handle and gives each a fair window to pay. For a smaller sale, per-user rate limits plus the atomic stock guard are usually enough.

How do I load-test a store before a sale?

Drive the real checkout path (stock decrement and payment webhook included) with a tool like k6, ramping to the peak you actually expect on staging that mirrors production. Watch p95 latency and database connections, fix the first thing that breaks, and run it again.

Will more servers fix a flash sale problem?

Not the hardest part. More servers help with CPU-bound load, but they do not fix overselling or contention on a few hot database rows, and more writers can make write contention worse. Fix the stock path and the caching first, then scale.

How do I keep payments correct during the spike?

Treat every payment webhook as applied-exactly-once: a stable key, a recorded result and a safe no-op on a repeat. During a flash sale webhooks arrive retried and out of order, and a handler that processes one twice can double-charge many buyers in a minute.

flash salehigh traffic ecommerceoversell preventionload testingscalingecommerce

Ready to discuss your project?

Book a free 15-minute technical audit with our engineering team.