**Availability**
- Core ride request and driver matching path should target 99.99% availability.
- Location display can degrade gracefully with slightly stale data.
**Latency**
- Driver location update ingestion: p95 < 200 ms.
- Nearby driver lookup: p95 < 300 ms.
- Ride match decision: p95 < 1-2 seconds.
- Driver accept/reject propagation: p95 < 500 ms.
**Scalability**
- Support millions of users and hundreds of thousands of concurrent drivers.
- Handle high-frequency location updates, for example every 2-5 seconds per active driver.
- Partition traffic geographically using city/region cells.
**Reliability and Fault Tolerance**
- Use durable event streams for ride state transitions.
- Use idempotency keys for passenger ride requests and driver accept actions.
- Use retries with exponential backoff and jitter.
- Use graceful degradation when maps, notifications, or real-time channels are partially unavailable.
**Resilience**
- Avoid synchronous dependency chains in the critical path.
- Use circuit breakers around Maps, ETA, Notification, and Pricing services.
- Use regional failover for critical services.
### Passenger APIs
```http
POST /v1/rides
Authorization: Bearer <token>
Idempotency-Key: <uuid>
Content-Type: application/json
{
"pickup": {
"lat": 37.7749,
"lng": -122.4194
},
"destination": {
"lat": 37.7849,
"lng": -122.4094
},
"ride_type": "standard"
}
```
Response:
```json
{
"ride_id": "ride_123",
"status": "REQUESTED",
"estimated_wait_seconds": 180
}
```
```http
GET /v1/rides/{ride_id}
```
```json
{
"ride_id": "ride_123",
"status": "DRIVER_ASSIGNED",
"driver": {
"driver_id": "driver_456",
"location": {
"lat": 37.7751,
"lng": -122.4188
},
"eta_seconds": 180
}
}
```
```http
GET /v1/drivers/nearby?lat=37.7749&lng=-122.4194&radius_meters=3000
```
Response:
```json
{
"drivers": [
{
"driver_id": "driver_456",
"lat": 37.7751,
"lng": -122.4188,
"eta_seconds": 180
}
]
}
```
### Driver APIs
```http
POST /v1/drivers/{driver_id}/location
Authorization: Bearer <token>
Content-Type: application/json
{
"lat": 37.7751,
"lng": -122.4188,
"heading": 125,
"speed_mps": 8.5,
"timestamp_ms": 1716000000000
}
```
```http
POST /v1/rides/{ride_id}/accept
Authorization: Bearer <token>
Idempotency-Key: <uuid>
Content-Type: application/json
{
"driver_id": "driver_456",
"offer_id": "offer_789",
"offer_version": 3
}
```
```http
POST /v1/rides/{ride_id}/reject
Authorization: Bearer <token>
Content-Type: application/json
{
"driver_id": "driver_456",
"offer_id": "offer_789",
"reason": "TOO_FAR"
}
```
### Real-Time Channels
```text
WebSocket /v1/realtime/passenger
WebSocket /v1/realtime/driver
```
Used for:
- Driver location updates to passengers.
- Ride request offers to drivers.
- Ride status updates.
- Driver accept/reject responses.
- Fallback to push notifications if WebSocket is unavailable.
API Gateway
Location Service
Nearby Driver Service
Ride Service
Matching Service
Dispatch/Notification Service
Driver Availability Service
ETA/Maps Service
Event Bus
Redis GEO / H3 Index
Relational DB
Cassandra/Scylla/Bigtable
Kafka
Drivers send location updates every few seconds while online.
Flow:
1.DriverApp sends location update.
2.API Gateway authenticates and rate-limits the request.
3.Location Service validates freshness and accuracy.
4.Current location is written to Redis GEO/H3 index with TTL.
5.Location event is published to Kafka.
6.Location history is asynchronously persisted.
Important details:
timestamp_ms.Example Redis key strategy:
geo:drivers:{region}:{h3_cell}
driver_status:{driver_id}
driver_location:{driver_id}
Passenger map does not need perfectly accurate real-time global state.
Flow:
1.Passenger app requests nearby drivers.
2.Nearby Driver Service queries Redis GEO/H3 cells around passenger pickup.
3.Service filters unavailable or stale drivers.
4.Service optionally estimates ETA.
5.Service returns a small sample of nearby drivers.
Optimizations:
Flow:
1.Passenger calls POST /v1/rides with an idempotency key.
2.Ride Service creates a ride in REQUESTED state.
3.Ride Service publishes RideRequested event.
4.Matching Service consumes the event.
5.Matching Service queries nearby available drivers.
6.Matching Service creates a short-lived offer for one or a small batch of drivers.
7.Dispatch Service sends offer to driver.
8.Driver accepts, rejects, or times out.
9.First valid accept transitions ride to DRIVER_ASSIGNED.
Ride state machine:
REQUESTED
-> OFFERING
-> DRIVER_ASSIGNED
-> DRIVER_ARRIVED
-> IN_PROGRESS
-> COMPLETED
REQUESTED/OFFERING/DRIVER_ASSIGNED
-> CANCELED
OFFERING
-> NO_DRIVER_FOUND
Basic matching score:
score = weighted_sum(
pickup_eta,
distance_to_pickup,
driver_acceptance_rate,
driver_cancellation_rate,
ride_type_match,
fairness_score,
current_traffic
)
Candidate search:
Dispatch strategy:
Driver acceptance must be race-safe.
Use:
offer_idoffer_versionride_iddriver_idAccept logic:
Accept succeeds only if:
ride.status == OFFERING
offer.status == ACTIVE
offer.driver_id == requesting_driver_id
offer.expires_at > now
driver.status == OFFERED
Then atomically:
DRIVER_ASSIGNED.ON_TRIP or ASSIGNED.This can be implemented using:
Example constraint:
UNIQUE(driver_id) WHERE driver_status IN ('ASSIGNED', 'ON_TRIP')
A thundering herd can happen when many passengers request rides during peak time, or when one ride request is broadcast to too many drivers.
Mitigations:
Example:
region:sf:matching_queue
region:sf:matching_tokens
driver_offer_lock:{driver_id}
ride_match_lock:{ride_id}
Idempotency is required because clients retry during mobile network failures.
Passenger ride request:
Idempotency-Key.(user_id, idempotency_key).ride_id.Driver accept:
Idempotency-Key.(driver_id, ride_id, offer_id, idempotency_key).Location update:
Apply layered rate limits.
At API Gateway:
Examples:
POST /v1/rides: 5 requests/min/passenger
POST /v1/drivers/{id}/location: 30 requests/min/driver
GET /v1/drivers/nearby: 60 requests/min/passenger
POST /v1/rides/{id}/accept: 20 requests/min/driver
Adaptive controls:
Critical-path reliability:
Transactional outbox:
1.Write ride state and outbox event in same DB transaction.
2.Outbox publisher sends event to Kafka.
3.Consumer processes event idempotently.
4.Consumer stores processed event ID to avoid duplicate side effects.
Failure examples:
Scale by geography:
Service scaling:
Data partitioning:
rides partitioned by region_id + ride_id
location events partitioned by driver_id or region_id
matching queues partitioned by region_id
driver availability partitioned by region_id + driver_id
Track both system and product metrics.
System metrics:
Product metrics:
Suggested SLOs:
99.99% availability for ride request API
p95 < 2 seconds from ride request to first driver offer
p95 < 500 ms for driver accept processing
p95 < 5 seconds location freshness for active drivers
p99 < 1 second nearby driver lookup
Kafka consumer lag < 10 seconds for matching-critical topics
driver_id.