Week 6: How GusLift Matches Rides in Real Time
Source: Dev.to
The Matching Room Abstraction
We don’t run one global pool. We partition by location, day, and departure time. A room key looks like:
Westie:mon:08:00That string becomes the identity of a Cloudflare Durable Object (DO), a live, in‑memory process that owns all real‑time state for that slot. Everyone heading from Westie at 8 am Monday shares one room. Leaving at 10:30? Different room entirely. This keeps each instance small and focused. The matching room doesn’t know or care about any other departure window.
Getting Into the Right Room
When a user opens the app, a Cloudflare Worker handles the request. It authenticates, resolves the user’s schedule, generates the slot key, and forwards the WebSocket connection to the appropriate DO. The Worker is stateless—a pure router. All the interesting state lives in the object it points to.
What the DO Tracks
The DO maintains four pieces of state:
drivers— map of driver ID → seats remainingriders_waiting— FIFO queue of riders requesting a ridepending_matches— riders a driver has selected but who haven’t confirmedconnections— live WebSocket handles, one per user
Every state change is broadcast to all connected clients. The frontend mirrors exactly what the DO holds, nothing more.
The Flow
- Driver goes online → sends
driver_onlinewith seat count → registered in the room, broadcast to everyone. - Rider requests a seat → sends
rider_request→ added to the queue. - Driver picks a rider → that rider moves from
riders_waitingtopending_matchesand receives amatch_requeston their socket. - Rider has 30 seconds to accept.
- No response → rider returns to the queue.
- Accept → seat count decrements, ride is written to Postgres, and the room updates for everyone.
Concurrent events—e.g., two drivers selecting the same rider simultaneously—are handled gracefully because DOs execute messages one at a time in a single‑threaded model, eliminating the need for explicit locking.
Why Durable Objects
Serverless platforms and WebSockets are a poor match by default: serverless functions are stateless and short‑lived, while a WebSocket requires persistent state. DOs provide a persistent, single‑threaded process with in‑memory state that survives across events. For a campus app where load is concentrated in a 20‑minute morning window, rooms spin up when needed and hibernate when idle, eliminating idle infrastructure and connection hand‑off problems.
What’s Left
Open problems not yet addressed:
- Drivers canceling after a match is accepted.
- Rooms that never get cleaned up after their departure window passes.
- Rate limiting on socket events.
These challenges are straightforward in principle; they just weren’t part of the initial implementation.