A day in three lifestyles
Café Sukoon now has four humans. Let's watch it live three lifestyles — and see how the same DNA behaves differently under each.
Monday morning: just chilling 😎
A handful of customers. Most of the time, nobody is ordering.
cdk deploy -c lifestyle=chilling
- Functions use 256 MB, no provisioned concurrency, workers capped low.
- Between orders, nothing runs and almost nothing is billed.
- The first order after a quiet spell may take a little longer (a cold start) — fine for this life.
- One or two alarms, short log retention.
Lesson: serverless humans sleep for free. For low-traffic systems, don't pay for readiness you don't need.
Wednesday: living in peace 🧘
Steady traffic through the day with a lunch peak.
cdk deploy -c lifestyle=peace
- 512 MB functions, moderate worker caps, full alarms, 30-day logs.
- Lambda and DynamoDB on-demand scale smoothly with the lunch rush.
- Queues absorb short bursts; dashboards show calm, predictable curves.
Lesson: a balanced default — let managed services scale, watch health, keep costs proportional.
Friday 8 p.m.: the rat race 🏃
A food festival nearby. Hundreds of orders a minute; the kitchen can only cook so fast.
cdk deploy -c lifestyle=ratRace
- The Waiter's order function has warm copies (provisioned concurrency) — no cold starts as the crowd arrives.
- The Waiter only validates, saves and announces — fast — while the Chef's inbox fills up and workers process at a capped, sustainable rate.
- Customers see "Order received, #42 in the queue" instead of errors.
- Throttling at the front door protects everything if the crowd exceeds even this.
Lesson: under pressure, accept quickly and control the pace. The queue is the café's waiting area.
Load-testing the rat race
Use a load-testing tool such as k6 to simulate Friday night against a staging deployment:
// friday-night.js — run with: k6 run -e URL=https://your-api friday-night.js
import http from "k6/http";
import { check } from "k6";
export const options = {
stages: [
{ duration: "1m", target: 50 }, // customers start arriving
{ duration: "3m", target: 300 }, // the festival crowd
{ duration: "1m", target: 0 }, // closing time
],
};
export default function () {
const res = http.post(
`${__ENV.URL}/orders`,
JSON.stringify({ tableNumber: Math.ceil(Math.random() * 40), items: [{ menuItemId: "chai", quantity: 1 }] }),
{ headers: { "content-type": "application/json" } }
);
check(res, { "order accepted": (r) => r.status === 201 });
}
Watch during the test:
| Metric | What healthy looks like |
|---|---|
| API 5xx errors | Near zero |
| Waiter p99 latency | Stays low (warm copies) |
| Lambda throttles | Zero, or only where you deliberately capped |
| Chef inbox depth | Rises during the peak, drains afterwards |
| Problem letters (DLQ) | Zero |
| DynamoDB throttled requests | Zero |
Run the same test against the chilling profile and compare — it's the most vivid way to see why lifestyle matters.
Load tests generate real usage. Run them in a sandbox or staging account, keep them short, and switch back from ratRace afterwards — provisioned concurrency bills while it's on.
In real life: one café, many moods
A real café doesn't redeploy every day. Instead, keep one deployment and schedule the moods: raise provisioned concurrency (Application Auto Scaling scheduled actions) before Friday evening and lower it after closing; set worker caps for the busiest expected load. The lifestyle profiles become schedules rather than separate deployments.