Skip to content
MCP Five

The ServerProject #111 / 51

The sandcastle

`let cookiesInJar = 12` works on your laptop and lies on serverless. The bug is the curriculum.

Here is the entire state management of project #1:

ts
let cookiesInJar = 12;

On your laptop this is perfect. You add twenty cookies, you look in the jar, there are thirty-two. Every time.

Deploy it to Vercel and it starts telling lies.

Many machines, many copies, all asleep

Vercel runs your code on however many machines it feels like, spun up and torn down on demand. Each one gets its own copy of that variable.

Two requests, two machines, two entirely separate copies of the same variable. Machine B has never heard of Machine A and never will. The fix is not a better variable β€” it is somewhere outside the process for the number to live.

And it is worse than "two machines disagree", because machines also fall asleep. A function that has been idle gets frozen or discarded. Come back twenty minutes later and the count has silently reset to 12 with no request having touched it.

Memory in a serverless function is a sandcastle β€” real, working, and taken by the tide.

The bug is the curriculum

This was left in deliberately, and the README says so out loud rather than quietly shipping something that works.

Project #3 fixes it, with the same tool, the same protocol and the same answers β€” the count just lives in Postgres now. And the interesting part of that fix is what didn't change.

The model cannot tell the difference

That is the payoff, and it is worth sitting with for a second.

cookie_jar in project #1 and cookie_jar in project #3 present an identical interface: same name, same description, same schema, same shape of reply. The model calls it and gets a number back. It has no idea whether that number came from a variable, a database, or a piece of paper.

The fix, in one statement

For completeness, since project #3 does it and it's smaller than you'd expect:

sql
update jar_state set cookies = cookies - $1
 where id = 'default' and cookies >= $1
 returning cookies

One statement. Read and write together, atomic because it is indivisible β€” so two people eating cookies at the same instant cannot lose one, and the "not enough cookies" check cannot race the write either.

The and cookies >= $1 guard is doing two jobs: it is the business rule and the concurrency control. Splitting them into a select then an update would reintroduce both bugs at once.

That, and the reason serverless code needs a driver that doesn't hold connections, is on Pausing is an array.