Source: A Modern Web App in C, by Corey Prophitt
A long-running server keeps old code in memory, so a deploy means stopping it and starting a new process. Under CGI the web server starts a fresh process for every request. Corey Prophitt runs a paid web app this way, and a deploy is replacing one file.
A long-running app server loads your code once and serves many requests from that one process. New code runs only after the old process stops and a new one starts. Requests that arrive or are still in flight across that gap can fail unless something in front holds and retries them.
Debugging has the same shape. To replay one failed request, you rebuild its state inside a process that is already serving other people.
No process outlives a request, so there is nothing to restart.
httpd routes every request, static assets included, to the CGI binary.
The process gets the request as environment variables and the body on stdin. It writes the response to stdout and exits.
Drop the new statically linked binary in place. No restart. New requests pick up the new binary.
Before you add more logging, run the request yourself. The app is an ordinary program: set the CGI environment variables, pipe in the body, watch stderr, and step through it with gdb.
| Step | What you do |
|---|---|
| Set the request | REQUEST_METHOD=POST, QUERY_STRING, CONTENT_TYPE, CONTENT_LENGTH |
| Pipe the body | ./app < body.txt and read stderr |
| Step through it | run the same input under gdb |
Prophitt compares this to serverless: a supervisor invokes your code per request, hands it a bag of environment variables, and collects the result. In his words, “CGI is serverless, minus the vendor.”
cgi.h, and is not sure that was right.Corey Prophitt, “A modern web app in C” · Hacker News discussion.
Sources: every fact and number on this page comes from Corey Prophitt’s post (one binary, one SQLite file, three libraries, rebuilds under half a second). All credit to the author.