Stack: Go, gRPC, RabbitMQ, MongoDB, Stripe, OpenTelemetry, Jaeger, Next.js, Kubernetes, Tilt · Repo: Axeloooo/Ride-Sharing
Problem
A rider previews a route and fares, requests a trip, a driver has to be found and accept in real time, and a payment session has to follow. This project builds that flow as four Go services plus a web client, using synchronous calls where a caller needs an answer and events where services only need to react.
Architecture diagram
Next.js web --HTTP preview/start--> API gateway <--WebSocket-- web
| | (/ws/riders, /ws/drivers)
gRPC | | gRPC
+-----------------------+ +------------------+
v v
Trip service ---HTTP---> OSRM routing API Driver service
MongoDB (trips) in-memory drivers
| ^
| trip.event.created |
v |
================ RabbitMQ topic exchange "trip" ================
| find drivers --------------------------------------------> |
| <-- driver.cmd.trip_request / no_drivers_found ------------+
| notify queues --> gateway --> rider / driver WebSocket
| driver accept / decline (via gateway) --> trip service
| driver_assigned + create payment session --> Payment service
| |
| Stripe Checkout Session
| <-- payment.event.session_created ----------------+
+-- failed after retries --> dlx --> dead_letter_queue
OpenTelemetry spans from gateway, trip, driver, payment --> JaegerThe gateway exposes /trip/preview, /trip/start and two WebSocket endpoints. The trip service (domain / service / infrastructure layout) gets routes from an external OSRM HTTP API, computes fares for sedan, SUV, van and luxury, and stores trips in MongoDB. The driver service keeps an in-memory registry, assigns each new driver a location and geohash, and matches by package type. The payment service turns a driver-assigned event into a Stripe Checkout session that the gateway pushes to the rider.
Key decisions
- Hybrid sync and async. gRPC with generated protobuf code for request/response; RabbitMQ routing keys such as
trip.event.*anddriver.cmd.*for events and commands. - Durable messaging with retries. Queues are durable with
x-dead-letter-exchange, publishing is persistent, and service consumers use manual acks with prefetch 1. A retry helper makes one attempt plus three retries with exponential backoff from 1 s capped at 10 s, then rejects the message intodead_letter_queue. The gateway's WebSocket notification consumers auto-ack. - Tracing across the gateway, gRPC and AMQP hops. OpenTelemetry spans propagate through them and export to Jaeger.
- Clean architecture and swappable storage. The trip service has in-memory and MongoDB repositories behind one interface.
- Hosted payment page. Stripe Checkout instead of a custom card form, with success and cancel URLs from a Kubernetes ConfigMap.
- Geohash for driver location, on the server and in the map client.
- Developer ergonomics. Tilt with live-update builds, minimal Alpine images, Windows build fallbacks and a service scaffold generator.
Challenges
- Delivering events to the right WebSocket. Each connected rider or driver gets queue consumers on shared queues, and the connection manager is in-process; its own comment notes that multiple gateway instances would need shared storage.
- State in a scaled service. The driver registry is per-process memory while the dev manifest runs two replicas, so replicas do not share drivers. Matching takes the first driver whose package type fits, and one registry read does not take the mutex.
- Dev setup gaps. Development manifests exist for every service plus Jaeger, RabbitMQ and MongoDB, but the Tiltfile does not load the MongoDB manifest, and a local
secrets.yaml(not committed) is required. - External routing dependency. Routes come from a hard-coded third-party OSRM endpoint rather than a self-hosted one.
Results
- The request path is implemented end to end: preview and fares, trip creation, driver matching with accept and decline, and Stripe Checkout session creation pushed to the rider over WebSocket.
- Operational scaffolding is committed: Tiltfile, Kubernetes manifests (production manifests exist for the gateway and trip service), Jaeger for traces, a dead-letter queue, and design notes with Mermaid sequence and flow diagrams in
docs/architecture. - The repository has no automated tests or CI workflow yet.