Skip to content

Latest commit

 

History

22 Commits

Folders and files

Repository files navigation

RideMatching Service

A ride matching REST API built with Spring Boot. Allocates available drivers to ride requests based on proximity, with safe concurrent handling.


Setup & Run

Requirements

  • Java 17
  • No database or external services needed

Run

./gradlew bootRun

The server starts on http://localhost:8080.

Build

./gradlew build

API Usage

1. Create a driver

POST /drivers
{
  "name": "John Doe",
  "phoneNumber": "+35699123456",
  "vehicleType": "SEDAN"
}

2. Register driver availability

POST /drivers/availability
{
  "driverId": "<uuid>",
  "latitude": 35.8997,
  "longitude": 14.5147
}

Returns 409 if the driver currently has an active ride.

3. Request a ride

POST /rides
{
  "riderId": "<uuid>",
  "pickupLatitude": 35.9010,
  "pickupLongitude": 14.5130
}

Returns the ride details along with the allocated driver. Returns 404 if no drivers are available.

4. Complete a ride

PUT /rides/{rideId}/complete

Returns 404 if the ride does not exist, 409 if already completed.

5. Get nearest available drivers

GET /drivers/available?latitude=35.90&longitude=14.51&limit=5

Returns a list of available drivers sorted by ascending distance from the given location.


How It Works

Storage

All data is stored in-memory using ConcurrentHashMap. There is no database. Data does not persist between application restarts.

Three repositories hold the state:

  • DriverRepository - all registered drivers
  • DriverAvailabilityRepository - driver availability records and claim slots
  • RideRepository - all rides

Driver Availability

DriverAvailabilityRepository uses two maps:

  • primaryMap (keyed by availability id) - permanent record of a driver's last registered location. Never removed from.
  • claimMap (keyed by driverId) - the live availability signal. An entry present means the driver is free. An entry absent means the driver is in a ride.

When a driver registers availability, they are added to both maps. When allocated to a ride, they are removed from the claimMap only. When the ride completes, they are re-inserted into the claimMap from the primaryMap.

Ride Request & Driver Allocation

When a ride is requested:

  1. All drivers in the claimMap are fetched and filtered (excluding any with an active ride as a safety check).
  2. Haversine distance is calculated from each driver's registered location to the rider's pickup location.
  3. Drivers are sorted by ascending distance.
  4. The service iterates the sorted list and attempts to atomically claim each driver using ConcurrentHashMap.remove(key, expectedValue).
  5. Only one thread can successfully remove a given entry. If the claim fails (another thread got there first), the next nearest driver is tried.
  6. Once a driver is claimed, a Ride record is created with status ACTIVE and returned to the rider along with the driver's details.

Ride Completion

Marking a ride complete sets its status to COMPLETED, records the completion timestamp, and calls release() on the availability repository, which re-inserts the driver into the claimMap making them available for new requests.


Design Notes

This is a small-scale project built for clarity and correctness over scalability. More advanced approaches were intentionally left out:

  • No GeoHashing or spatial indexing - driver distance is computed by iterating all available drivers and applying the Haversine formula. This is sufficient at small scale but would not hold up with thousands of concurrent drivers. A production system would use a spatial index (e.g. GeoHash, R-tree, PostGIS) to query only nearby drivers.
  • No persistent storage - in-memory maps reset on restart. A real system would use a database.
  • No authentication - riderIds and driverIds are caller-supplied UUIDs with no validation of identity.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages