Fast-CGI for RESTful Endpoints
What is Fast-CGI?
Fast-CGI is a high-performance extension of the older Common Gateway
Interface (CGI) standard. Instead of creating a brand new process for
every incoming request, a Fast-CGI program stays alive and communicates
with the webserver through a persistent connection.
Traditional CGI not only created and destroyed a process for every
request, it also forced the application itself to restart completely.
This meant re-allocating memory, reinitializing variables, reconnecting
to databases, then on completion disconnecting and freeing everything
again. These steps are far more expensive than process creation alone.
Fast-CGI avoids this overhead by keeping the program alive between
requests. Memory stays allocated, variables remain in scope, and
database connections can be kept open for reuse. The result is a system
that is dramatically more efficient and responsive under load.
This design allows Sheerpower programs to respond quickly, handling
thousands of requests per second on a modern consumer-level computer,
and maintain state between calls if needed.
In practice, the SPINS_WEBSERVER places each incoming request
into a work queue specific to each named handler. Your Sheerpower Fast-CGI handler polls this queue,
reads the request, and writes the response. This gives you RESTful APIs
that are fast, efficient, and easy to extend.
This Tutorial Explained
This tutorial shows how to build a simple REST endpoint in
Sheerpower using the
SPINS_WEBSERVER
and a Fast-CGI interface. In this example, we will serve word definitions
from a CSV file and return a simple plain-text response.
What you’ll learn
- How Fast-CGI handlers are named (
cgi://NAME
)
- How the request queue is polled with
line input #cgi_ch:
- How to read query params via
getsymbol$()
- How to look up rows efficiently with
findrow()
- The SPINS_WEBSERVER automatically supplies the CGI headers if none are specified,
based on the filetype (.txt in this example).
1) Start SPINS
C:>spins_webserver
Sheerpower InterNet Services Web Server SPINS_WEBSERVER Vnn.nn
Copyright (c) 2005-2025 Touch Technologies, Inc.
Listening IP address is 0.0.0.0
Spoofed>> "Server: Apache/2.4.52 (Ubuntu)"
Port 4, wwwroot is C:\Sheerpower\sphandlers\wwwroot\
Port 80, wwwroot is C:\Sheerpower\sphandlers\wwwroot\
2) Create the data file
Place a
words.csv
next to your handler:
ZORI,"Japanese sandals"
ZOUK,"A Caribbean music style"
ZYME,"An enzyme"
AAHED,"to exclaim in surprise [v]"
3) Build and run this minimal Fast-CGI handler
// Program: word_handler.spsrc — minimal Fast-CGI demo
// Test: http://localhost/scripts/spiis.dll/word/get_def.txt?word=ZOUK
// Register the handler as "WORD"
handler_name$ = "cgi://WORD"
// Track persistence across requests
request_counter = 0
// Load dictionary into memory (runs once at startup)
cluster words: word$, def$
cluster input name "@words.csv", headers 0: words
print "Words loaded: "; size(words)
print sprintf$("%t WORD handler ready")
// Attach handler to SPINS_WEBSERVER
open file cgi_ch: name handler_name$
do
// Poll for next request (empty string = nothing yet)
line input #cgi_ch: method$
if method$ = "" then repeat do
request_counter++
// Get query symbol "word" (auto-trimmed by default)
word$ = getsymbol$("word")
if word$ = "" then
print #cgi_ch: "error,Missing 'word' parameter -- request "; request_counter
repeat do
end if
// Lookup (case-insensitive lookups by default)
row = findrow(words->word$, word$)
if row = 0 then
print #cgi_ch: "error,Word not found: "; word$; " -- request "; request_counter
repeat do
end if
// Success: return definition, quoted for CSV safety
print #cgi_ch: "success,"; quote$(words->def$); " -- request "; request_counter
loop
end
4) Try it in your browser
Use this syntax:
http://localhost/scripts/spiis.dll/word/get_def.txt?word=ZOUK
Example response
success,"A Caribbean music style" -- request 1
SPINS I/O Handling and Asynchronous Design
line input #cgi_ch:
polls the SPINS work queue.
If the queue is empty, SPINS waits 10 ms and checks again.
If it is still empty, line input
returns an empty string (""
).
This design is efficient: it avoids wasting CPU cycles on busy polling,
while remaining non-blocking and responsive as soon as work arrives.
- All communication with
SPINS_WEBSERVER
is asynchronous,
using globally shared memory.
This makes I/O non-blocking and nearly instantaneous, allowing handlers
to keep working while exchanging data without delay.
Browser
⇄
SPINS_WEBSERVER
⇄
Handlers
Shared Memory (non-blocking I/O)
All handler communication with SPINS_WEBSERVER
is asynchronous
through shared memory, making data exchange nearly instantaneous.
Fast-CGI Idle Processing Pattern
The Sheerpower Fast-CGI polling mechanism provides a unique advantage
for background processing: confirmed idle detection (indicating no pending tasks).
Unlike pure event-driven architectures, the polling loop explicitly
identifies when no requests are pending, creating natural opportunities
for background work.
The Idle Detection Pattern
do
// Poll for next request
line input #cgi_ch: method$
if method$ = "" then
// CONFIRMED IDLE STATE - no requests waiting
// Perfect spot for background processing
check_for_new_code
update_cached_data
repeat do
end if
// Process the request
handle_request
loop
How It Works
-
First Poll: The handler immediately checks
the request queue as soon as it reaches the polling point.
-
If Work Available: The next request is pulled
and processed right away with zero delay, returning the HTTP
method (such as
GET
, PUT
, etc.) for
handling.
-
If Empty: The handler waits for 1/100th of a
second (about 10 ms) and checks the queue a second time, to
avoid busy-waiting.
-
If Still Empty: An empty string is returned,
which signals that no requests are waiting. This marks a
confirmed idle state, giving the program a reliable
point to run background or maintenance tasks before looping
back to polling.
Why this is efficient:
- Problem: Traditional busy-wait loops keep checking
for work continuously, wasting CPU cycles.
- Solution: Insert a brief 1/100th of a second pause when no
requests are found, then recheck the queue. If still empty,
return an empty string to mark a confirmed idle state.
- Efficiency: This approach prevents CPU waste,
remains highly responsive, and guarantees a reliable idle
moment for background tasks.
- Takeaway: Sheerpower’s polling loop eliminates
complex schedulers while ensuring both responsiveness and
efficient use of system resources.
Background Processing Guidelines
✅ Good Idle Tasks
- Checking if there is a new version of this program and starting it
- Quick maintenance (< 5 ms): cache cleanup, counter updates
- Incremental work: process one item from a background queue
- Non-blocking I/O: fire-and-forget logging, metrics
❌ Avoid in Idle Loop
- Long-running operations: database backups, file compression
- Blocking I/O: synchronous file operations, network calls
- CPU-intensive work: image processing, complex calculations
Scaling with Multiple Handlers
Fast-CGI handlers in Sheerpower can be scaled to match the power of
your system. There are two main approaches:
-
Multiple instances of the same handler: You can
start several copies of the same Fast-CGI program (for example,
word_handler.spsrc
). Each instance will attach to the
same handler name and pull requests from the same queue. On a
multi-processor system, this allows requests to be processed in
parallel, taking full advantage of available CPUs.
-
Non-blocking polling: Within each handler process,
the
do ... loop
uses non-blocking polling to check for
work, which is highly efficient. The processing of each request is
synchronous. A task that takes significant time to complete will tie
up that handler instance, allowing other handler instances to pick
up subsequent requests.
-
Different handlers with unique names: You can run
multiple Fast-CGI programs simultaneously, each with a different
handler name. For example, one handler may provide word definitions,
while another handles logging or JSON responses. Each handler has
its own request queue managed by the webserver.
This flexibility means you can design your Sheerpower web applications
to scale easily with hardware resources, or separate tasks into cleanly
defined services.
Operational Benefits
This queue-based design provides enterprise-grade operational
capabilities:
-
Hot-swappable code deployment: Deploy updates by
starting new handler instances alongside existing ones. Old handlers
complete their current requests and can be gracefully stopped while
new handlers immediately begin serving from the same queue. This
enables zero-downtime deployments.
-
Built-in fault tolerance: If a handler crashes,
other instances continue serving requests without interruption. The
queue automatically redistributes load among remaining handlers,
providing natural resilience without complex failover mechanisms.
-
Flexible testing and rollback: Run different
handler versions simultaneously for A/B testing, or instantly revert
problematic deployments by stopping new handlers and restarting
previous versions.
Performance at Scale
Each handler processes thousands of requests per second doing database queries on
modern consumer hardware, supporting hundreds of thousands of hourly user requests per
handler. Multiple handlers scale nearly linearly:
- 4 handlers: ~1+ million user requests/hour
- 8 handlers: ~2+ million user requests/hour
Summary: With just a few lines of code you can create a
RESTful API using Fast-CGI in Sheerpower. Extend this to JSON, CORS,
authentication, or larger datasets by changing the body logic.
Unlike other major development environments, this Fast-CGI demo requires
no external dependencies, frameworks, or libraries.
Everything you need is built directly into Sheerpower, so once
the SPINS_WEBSERVER is running the handler runs immediately.
(Show/Hide Fast-CGI Takeaways)
Takeaways
-
Fast-CGI keeps programs alive between requests, making responses
very fast.
-
SPINS places requests into handler-specific work queues that
handlers poll for work.
-
Each handler is given a name, e.g.
handler_name$ = "cgi://WORD"
.
-
Use
getsymbol$()
to read query parameters directly.
-
findrow()
searches clusters quickly, ignoring case by
default.
-
The example returns simple CSV-style responses
(
success
/error
).
-
Extend easily to JSON, add CORS headers, or support multiple
handlers.
-
Fast-CGI avoids restarting the application on every request. This
eliminates repeated process creation, memory allocation, and variable
reinitialization, as well as database reconnect/disconnect cycles —
all of which are very costly operations.
-
For higher performance, run multiple instances of the same handler
to utilize all CPUs on a multi-processor system, or run different
handlers with unique names to perform separate tasks in parallel.