Week 6: How GusLift Matches Rides in Real Time

Published: (March 15, 2026 at 09:41 AM EDT)
3 min read
Source: Dev.to

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:00

That 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 remaining
  • riders_waiting — FIFO queue of riders requesting a ride
  • pending_matches — riders a driver has selected but who haven’t confirmed
  • connections — 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

  1. Driver goes online → sends driver_online with seat count → registered in the room, broadcast to everyone.
  2. Rider requests a seat → sends rider_request → added to the queue.
  3. Driver picks a rider → that rider moves from riders_waiting to pending_matches and receives a match_request on their socket.
  4. 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.

0 views
Back to Blog

Related posts

Read more »

Travigo

Travel as fast as you speak with Gemini! Where live agents meet immersive storytelling & 3D navigation. This project was created for entering the Gemini Live Ag...

Micro games

Hey Gamers! 👾 As part of the Rapid Games Prototyping module, we are tasked with reviewing a peer's game. The challenge is to analyse a prototype built in just...