Pilot: Café Sukoon
Hiring the Waiter
We grew a Waiter in Growing one human. Now we'll give the café a proper shared world and make the Waiter's lifestyle configurable, so the same DNA can live a chilled, peaceful or rat-race life.
Lifestyle profiles
// infra/lifestyle.ts — one place that describes each way of living
import { Duration } from "aws-cdk-lib";
export type Lifestyle = "chilling" | "peace" | "ratRace";
export const PROFILES = {
chilling: { memorySize: 256, provisionedConcurrency: 0, workerConcurrency: 2, logDays: 7 },
peace: { memorySize: 512, provisionedConcurrency: 0, workerConcurrency: 10, logDays: 30 },
ratRace: { memorySize: 1024, provisionedConcurrency: 50, workerConcurrency: 50, logDays: 30 },
} as const;
export const TIMEOUT = Duration.seconds(10);
memorySize— more memory also means more CPU for Lambda.provisionedConcurrency— warm copies of latency-critical functions (rat race only).workerConcurrency— the most copies of a background worker allowed at once, protecting downstream systems.logDays— how long to keep the diary.
The shared world
// infra/cafe-stack.ts
import { Stack, StackProps, CfnOutput } from "aws-cdk-lib";
import { Construct } from "constructs";
import * as events from "aws-cdk-lib/aws-events";
import * as apigw from "aws-cdk-lib/aws-apigatewayv2";
import { Lifestyle } from "./lifestyle";
import { Waiter } from "../services/waiter/infra/waiter";
export interface CafeStackProps extends StackProps { lifestyle: Lifestyle; }
export class CafeStack extends Stack {
constructor(scope: Construct, id: string, props: CafeStackProps) {
super(scope, id, props);
const townSquare = new events.EventBus(this, "TownSquare");
const frontDoor = new apigw.HttpApi(this, "FrontDoor", {
corsPreflight: { allowOrigins: ["*"], allowMethods: [apigw.CorsHttpMethod.ANY], allowHeaders: ["content-type"] },
});
const waiter = new Waiter(this, "Waiter", { eventBus: townSquare, api: frontDoor, lifestyle: props.lifestyle });
new CfnOutput(this, "FrontDoorUrl", { value: frontDoor.apiEndpoint });
new CfnOutput(this, "Lifestyle", { value: props.lifestyle });
}
}
// bin/cafe.ts — choose the lifestyle at deploy time: cdk deploy -c lifestyle=ratRace
import { App } from "aws-cdk-lib";
import { CafeStack } from "../infra/cafe-stack";
import type { Lifestyle } from "../infra/lifestyle";
const app = new App();
const lifestyle = (app.node.tryGetContext("lifestyle") ?? "peace") as Lifestyle;
new CafeStack(app, "CafeSukoon", {
lifestyle,
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});
The Waiter, lifestyle-aware
Changes to the Waiter construct from Growing one human:
import * as logs from "aws-cdk-lib/aws-logs";
import { Lifestyle, PROFILES, TIMEOUT } from "../../../infra/lifestyle";
export interface WaiterProps {
eventBus: events.IEventBus;
api: apigw.HttpApi;
lifestyle: Lifestyle;
}
// …inside the constructor:
const profile = PROFILES[props.lifestyle];
const placeOrder = new nodejs.NodejsFunction(this, "PlaceOrder", {
runtime: lambda.Runtime.NODEJS_22_X,
architecture: lambda.Architecture.ARM_64,
memorySize: profile.memorySize,
timeout: TIMEOUT,
tracing: lambda.Tracing.ACTIVE,
entry: path.join(__dirname, "../src/senses/place-order.http.ts"),
environment: { TABLE_NAME: this.memory.tableName, EVENT_BUS_NAME: props.eventBus.eventBusName },
logGroup: new logs.LogGroup(this, "PlaceOrderDiary", { retention: profile.logDays as logs.RetentionDays }),
});
// In the rat race, keep warm copies and send traffic to them
const target = profile.provisionedConcurrency > 0
? placeOrder.addAlias("live", { provisionedConcurrentExecutions: profile.provisionedConcurrency })
: placeOrder;
props.api.addRoutes({
path: "/orders",
methods: [apigw.HttpMethod.POST],
integration: new HttpLambdaIntegration("PlaceOrderIntegration", target),
});
(logs.RetentionDays values are numbers of days such as 7 and 30, so the profile maps directly.)
Deploy
cdk deploy -c lifestyle=peace
Place an order with curl (see Growing one human) and confirm the OrderPlaced announcement in the EventBridge console (or with a temporary rule that logs all events to CloudWatch Logs — handy while learning).
Key idea
The lifestyle is now part of the DNA — visible in code review, switchable at deploy time, and identical across environments.