Multiplex Proxy
This capstone project builds a Multiplex HTTP Proxy—think of it as a telephone switchboard from the 1950s, but for HTTP. Requests come in, the operator (our code) figures out who they're for, spins up a connection if needed, and patches them through.
The twist: every connection, every server, every background task will be properly managed by Effection. Press Ctrl+C and watch the whole building power down gracefully—no orphaned processes, no leaked connections.
What We're Building
┌─────────────────────────────────────────────────────────────────┐
│ main() │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Switchboard (Port 8000) │ │
│ │ - Receives all incoming HTTP requests │ │
│ │ - Parses Host header to determine target │ │
│ │ - Proxies request to appropriate backend server │ │
│ └──────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────▼─────────────────────────────────┐ │
│ │ ServerPool Resource │ │
│ │ - Manages Map<hostname, ServerInfo> │ │
│ │ - Spawns new Express servers on demand │ │
│ │ - Assigns dynamic ports (3001, 3002, ...) │ │
│ │ - Cleans up servers when pool shuts down │ │
│ └──────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────┼───────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │app-a │ │app-b │ │app-c │ │
│ │:3001 │ │:3002 │ │:3003 │ │
│ └──────┘ └──────┘ └──────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
User Flow
- User makes request to
http://localhost:8000withHost: app-a.localhost - Switchboard receives request, extracts hostname
app-a - ServerPool checks if
app-aserver exists - If not, spawns a new Express server on port 3001
- Switchboard proxies request to
localhost:3001 - Response flows back to user
- When main() ends (Ctrl+C), all servers are automatically cleaned up
Components
1. Express Server Resource (useExpressServer)
A resource that:
- Creates an Express app
- Listens on a given port
- Provides the app and server to the caller
- Closes the server on cleanup
2. Server Pool Resource (useServerPool)
A resource that:
- Maintains a Map of hostname → server info
- Has a
getOrCreate(hostname)method - Spawns new servers as child tasks
- Uses Context to share itself with children
3. Switchboard Resource (useSwitchboard)
A resource that:
- Listens on the main port (8000)
- Uses
http-proxyto forward requests - Calls ServerPool to get/create backend servers
- Handles errors gracefully
Effection Concepts Used
| Concept | Usage |
|---|---|
main() | Entry point, handles Ctrl+C |
resource() | Express servers, server pool, switchboard |
spawn() | Creating new server tasks |
useScope() | Running operations from Express handlers |
Context | Sharing ServerPool with operations |
ensure() | Cleanup of servers |
Channel | Logging events |
suspend() | Keeping the main process alive |
Next Steps
Let's build each component step by step:
- Server Resource — wrapping Express as a resource
- Server Pool — managing multiple servers dynamically
- Switchboard — routing requests to backends
- Final Assembly — putting it all together