Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
5818a55
Add Woo: Common Lisp HTTP server on libev (first Lisp entry!)
BennyFranciscus Mar 15, 2026
6636c47
fix: write .sbclrc manually instead of ql:add-to-init-file
BennyFranciscus Mar 15, 2026
57189a4
fix(woo): correct Quicklisp package name sqlite (not cl-sqlite)
BennyFranciscus Mar 15, 2026
014532d
fix(woo): bind to 0.0.0.0 — Docker health check needs external access
BennyFranciscus Mar 15, 2026
08d3ec2
fix: use single-stage build to fix CFFI shared library loading
BennyFranciscus Mar 15, 2026
6c1092f
Fix runtime: keep build-essential for shared libs, only purge curl/ca…
BennyFranciscus Mar 15, 2026
69fd51c
Fix: remove 'file' command check (not installed in container)
BennyFranciscus Mar 15, 2026
68f8d65
fix: remove SBCL image compression for faster startup
BennyFranciscus Mar 15, 2026
0474bac
fix(woo): run via SBCL directly instead of saved core
BennyFranciscus Mar 15, 2026
3d2d29a
fix: use multi-stage build with saved core for fast startup
BennyFranciscus Mar 15, 2026
1fab1e9
fix: switch to single-stage Dockerfile with direct SBCL startup
BennyFranciscus Mar 16, 2026
888aa51
fix(woo): single-stage save-lisp-and-die for fast startup
BennyFranciscus Mar 16, 2026
0f97d2f
fix(woo): use runtime FASL loading instead of save-lisp-and-die
BennyFranciscus Mar 16, 2026
b068859
fix(woo): multi-stage build with save-lisp-and-die executable
BennyFranciscus Mar 16, 2026
84e7329
fix(woo): single-stage build + remove compression for fast startup
BennyFranciscus Mar 16, 2026
76f4fa4
Fix startup: LD_PRELOAD libev for CFFI on core restore
BennyFranciscus Mar 16, 2026
ac223a4
woo: skip save-lisp-and-die, run directly via SBCL
BennyFranciscus Mar 16, 2026
5b4bae2
woo: save-lisp-and-die + cffi:reload-foreign-libraries for instant st…
BennyFranciscus Mar 16, 2026
4da6724
fix: drop save-lisp-and-die, load from cached FASLs at startup
BennyFranciscus Mar 16, 2026
71c55b0
fix: use save-lisp-and-die with startup wrapper for instant boot
BennyFranciscus Mar 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions frameworks/woo/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
FROM ubuntu:24.04

RUN apt-get update && apt-get install -y --no-install-recommends \
sbcl curl ca-certificates build-essential \
libev-dev libsqlite3-dev zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*

# Install Quicklisp
RUN curl -o /tmp/quicklisp.lisp https://beta.quicklisp.org/quicklisp.lisp \
&& sbcl --non-interactive \
--load /tmp/quicklisp.lisp \
--eval '(quicklisp-quickstart:install)' \
&& rm /tmp/quicklisp.lisp

# Pre-load all deps
RUN sbcl --non-interactive \
--load '/root/quicklisp/setup.lisp' \
--eval '(ql:quickload (list :woo :jonathan :cl-ppcre :babel :salza2 :sqlite) :silent t)'

COPY src/ /app/src/

# Build standalone executable via save-lisp-and-die.
# Single-stage build: foreign library paths match between build and runtime.
# startup.lisp calls cffi:reload-foreign-libraries before main to restore
# CFFI handles that become stale after core image save/restore.
RUN sbcl --non-interactive \
--load '/root/quicklisp/setup.lisp' \
--eval '(ql:quickload (list :woo :jonathan :cl-ppcre :babel :salza2 :sqlite) :silent t)' \
--load '/app/src/server.lisp' \
--load '/app/src/startup.lisp' \
--eval '(sb-ext:save-lisp-and-die "/app/woo-server" \
:toplevel (function httparena-startup::toplevel) \
:executable t \
:purify t)'

EXPOSE 8080

CMD ["/app/woo-server"]
29 changes: 29 additions & 0 deletions frameworks/woo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Woo — Common Lisp HTTP Server

[Woo](https://github.com/fukamachi/woo) is a fast, non-blocking HTTP server for Common Lisp, built on [libev](http://software.schmorp.de/pkg/libev.html). It runs on [SBCL](http://www.sbcl.org/) (Steel Bank Common Lisp), which compiles to native machine code.

## Why Woo?

- **First Lisp-family entry** in HttpArena
- Built on libev for non-blocking I/O with multi-worker process model
- SBCL compiles CL to native code — no interpreter overhead
- Solo developer [@fukamachi](https://github.com/fukamachi) has maintained it since 2014
- Uses the [Lack](https://github.com/fukamachi/lack)/[Clack](https://github.com/fukamachi/clack) interface — the Common Lisp equivalent of Ruby's Rack or Python's WSGI

## Architecture

- **Runtime:** SBCL (native compiled)
- **Event loop:** libev (non-blocking)
- **Workers:** Multi-process (one per CPU core)
- **JSON:** [Jonathan](https://github.com/Rudolph-Miller/jonathan) (fast JSON encoder/decoder)
- **Compression:** [Salza2](https://www.xach.com/lisp/salza2/) (gzip)
- **SQLite:** [cl-sqlite](https://github.com/dmitryvk/cl-sqlite)

## Build

The Docker build compiles everything into a standalone SBCL image (~50-80 MB compressed) that includes the full Lisp runtime and all dependencies. No Quicklisp needed at runtime.

```bash
docker build -t httparena-woo .
docker run -p 8080:8080 -v /path/to/data:/data httparena-woo
```
19 changes: 19 additions & 0 deletions frameworks/woo/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"display_name": "woo",
"language": "Common Lisp",
"type": "framework",
"engine": "libev",
"description": "Woo — a fast non-blocking Common Lisp HTTP server built on libev, using SBCL. First Lisp-family entry in HttpArena.",
"repo": "https://github.com/fukamachi/woo",
"enabled": true,
"tests": [
"baseline",
"pipelined",
"noisy",
"limited-conn",
"json",
"upload",
"compression",
"mixed"
]
}
Loading
Loading