Skip to main content
Case Study

Ride-Hailing and Driver Dispatch System

Mobility Laravel Elasticsearch Dispatch

A dispatch system has two jobs that pull against each other: absorb a constant stream of driver location updates, and answer a matching query quickly enough that a rider does not give up waiting. The client's platform did both against the same tables, so every busy period made matching slower exactly when it mattered most. ELIVTECH separated the write path from the read path and rebuilt matching, fare calculation and trip lifecycle around that split.

The client operates a ride-hailing service across several cities with a driver fleet of independent contractors. Its original platform wrote every driver location ping directly into the transactional database and ran matching as a distance calculation across that same table, which meant peak hours degraded both. Fares were computed at the end of a trip from a route the system had not verified, producing disputes it had no evidence to resolve. Driver earnings were reconciled by hand each cycle. ELIVTECH rebuilt the platform with a dedicated ingest path for location telemetry, geospatial matching served from Elasticsearch, trip lifecycle modelled as explicit state transitions on Laravel, and settlement derived from the trip record rather than recalculated afterwards.

At a glance

0 Weeks End-to-End
0 Core Services Delivered
0 Trip Lifecycle States
0 p95 Driver Match Latency

The challenge

Location writes and matching reads competing for the same database at exactly the same moments.

Telemetry writing into the transactional store

Every driver sent a position update on a short interval, and each one became a write against tables that matching also had to read. During peak hours the write volume and the read volume were both at their highest, so lock contention slowed the queries the business most depended on. Adding database capacity moved the ceiling without changing the shape of the problem.

Matching by distance calculation

Finding a nearby driver meant computing distance across candidate rows in application code. The work grew with fleet size rather than with the number of drivers actually near the rider, so matching became slower precisely as the service became busier and the rider waited longer for a worse answer.

Fares computed from an unverified route

The final fare was calculated at trip end from data the platform had not independently recorded. When a rider disputed a charge or a driver disputed an earning, there was no authoritative trip trace to consult, so support resolved cases by judgement and both parties learned not to trust the number.

Trip status inferred, not recorded

Trip progress was derived from whichever timestamp columns had been populated. Edge cases such as a driver cancelling after arrival, a rider not appearing, or a trip abandoned mid-route left records in states nothing in the code had anticipated, and those trips required manual correction before they could be settled.

Driver settlement reconciled by hand

Earnings were assembled each cycle by exporting trips, applying incentive rules in spreadsheets and adjusting for disputes. The process was slow, hard to audit and impossible for a driver to verify independently, which made every payment query an investigation rather than a lookup.

No visibility into supply and demand

Operations could not see where demand was building relative to available drivers until complaints arrived. Decisions about incentives and coverage were made retrospectively from reports rather than from a live view, so the response always trailed the situation it was addressing.

Our solution

Separate the write path from the read path, then make every trip a recorded sequence rather than an inference.

Load Analysis and Dispatch Design

Five weeks profiling real traffic to separate what is genuinely transactional from what is telemetry. Location updates are high-volume, individually disposable and only ever read as the latest value, which makes them a poor fit for the transactional store. That distinction drove the architecture: a dedicated ingest path for position data, and a matching index that answers proximity questions without touching trip tables.

Telemetry Ingest and Geospatial Matching

A Node.js ingest service accepts driver position updates over persistent connections and writes current state into Elasticsearch geo point fields, keeping only the latest position per driver alongside availability and vehicle class. Matching became a bounded geo query filtered by eligibility, so the work scales with drivers near the rider rather than with the size of the fleet.

Trip Lifecycle and Verified Fares

Trips were modelled on Laravel as an explicit state machine with named states and permitted transitions, so cancellation after arrival and rider no-show became defined outcomes rather than unhandled cases. The route is recorded as a sampled trace during the trip, and the fare is computed from that trace, giving both parties the same evidence when a charge is questioned.

Settlement and Live Operations View

Earnings are derived from completed trip records with incentive rules applied as configuration, so a driver can see how a figure was reached without contacting support. Operations gained a live view of demand against available supply per zone, built from the same telemetry stream, with the whole platform running on autoscaling AWS infrastructure defined in code.

Technology stack

Laravel PHP 8 Node.js Elasticsearch Geo Queries MySQL 8 Redis WebSockets Laravel Queues AWS ECS Fargate Amazon RDS Amazon ElastiCache Amazon SQS Amazon CloudWatch Terraform CI/CD Pipeline

Results

Measured across peak periods once all cities were serving from the new dispatch path.

0 p95 Driver Match Latency at Peak
0 Location Writes Against Trip Tables
0 Trips Settled From Recorded State
0 Pipeline Deploy Time, No Downtime

Before and after: platform engineering measures

Before
  • Driver position updates written into transactional tables
  • Matching computed distance across candidate rows in code
  • Matching slowed as the fleet and the peak grew together
  • Fares calculated at trip end from an unverified route
  • Trip progress inferred from populated timestamp columns
  • Driver earnings assembled in spreadsheets each cycle
  • Supply and demand assessed retrospectively from reports
After
  • Telemetry ingested on a dedicated path, current state only
  • Matching served by bounded geo queries with eligibility filters
  • Matching cost scales with nearby drivers, not fleet size
  • Fares computed from a sampled route trace recorded during the trip
  • Trip lifecycle recorded as explicit, permitted transitions
  • Settlement derived from trip records with rules as configuration
  • Live supply and demand view per zone from the telemetry stream

Project timeline

Weeks 1-5

Load Analysis and Dispatch Design

Traffic profiling to separate telemetry from transactional load, trip state machine definition, fare and incentive rule documentation, and the target architecture for ingest, matching and settlement.

Weeks 6-13

Telemetry Ingest and Matching Index

Node.js ingest service on persistent connections, Elasticsearch geo point index holding latest driver state, eligibility filtering by vehicle class and availability, and bounded geo query tuning against real fleet distributions.

Weeks 14-21

Trip Lifecycle and Fare Engine

Laravel state machine with transition guards, append-only trip event log, sampled route trace capture, fare calculation from the recorded trace, and surge and waiting rules expressed as configuration rather than code.

Weeks 22-29

Settlement and Operations Tooling

Earnings derivation from completed trips, incentive rule engine, driver-facing earnings breakdown, dispute handling against the trip trace, and the live supply and demand view for operations built on the telemetry stream.

Weeks 30-34

Load Testing and City Rollout

Load testing shaped to real peak curves, fault injection on the ingest path, monitoring on match latency and index lag, then a city-by-city rollout with the previous dispatch retained as fallback until each was stable.

Key takeaways

What shaped the engineering decisions

  • Telemetry is not transactional data: Scaling the database was rejected because it treats a modelling problem as a capacity problem. Location pings are disposable and only the latest matters, so routing them to a separate store removed the contention rather than raising the ceiling on it.
  • Let the index do the geometry: Distance calculation in application code scales with fleet size. A bounded geo query with eligibility filters scales with the drivers actually near the rider, which is the only population the answer depends on.
  • Record the route, then price it: Computing a fare from data the platform never captured left disputes unresolvable. A sampled trace recorded during the trip gives rider, driver and support the same evidence and turns a disagreement into a shared reference.
  • Model the awkward outcomes explicitly: Cancellation after arrival and rider no-show were the cases that produced unsettleable trips. Naming them as states with defined transitions removed the manual correction work they used to generate every cycle.
  • Derive settlement, do not reassemble it: Spreadsheet reconciliation was slow and unverifiable. Deriving earnings from trip records with incentive rules held as configuration made a driver's earnings explainable without an investigation.
  • Test the peak shape, not the average: Uniform load testing would have missed the interaction between ingest volume and match latency. Replaying real peak curves surfaced the contention that mattered while it was still cheap to fix.
Where this platform goes next. With telemetry on its own path and trips recorded as verifiable sequences, the platform can add matching considerations without slowing the query. The team is extending dispatch toward driver acceptance history and destination direction, using the accumulated trace data to improve arrival estimates per zone and hour, and giving operations forward-looking supply guidance rather than a live view alone.

Want results like these?

Let's discuss how ELIVTECH can drive measurable outcomes for your business.

Start your project