Reviewed by 6 specialized AI reviewers. Explore the diagram and the full per-section feedback below.
Loading diagram…
The user starts by searching for a product along with their current latitude and longitude. The Search Service first performs a geospatial lookup in Elasticsearch to identify nearby distribution centers (DCs). Since a simple radius search does not guarantee delivery within one hour, the service then determines the actual travel time from each candidate DC to the user's location. To avoid making expensive Google Maps API calls for every request, travel times are cached in Redis using geohash (or H3 cell) based keys. If a cache entry exists for the user's geohash region, the cached delivery times are used. Otherwise, Google Maps Distance Matrix is called, the results are stored in Redis with a short TTL, and then returned. Any DC whose delivery time exceeds one hour is filtered out. Once the system has identified all DCs capable of delivering within one hour, it performs a product availability lookup. Inventory data is replicated from PostgreSQL into Elasticsearch through a CDC pipeline (for example, Debezium → Kafka → Elasticsearch). This allows low-latency searches without putting load on the transactional database. Elasticsearch returns products that are available in the filtered DCs. We accept that search results may be slightly stale because the final inventory validation happens during order placement. When a user places an order, the Order Service receives the request and calls the Inventory Service to validate stock availability. If sufficient inventory exists for all requested items, the Inventory Service starts a database transaction. Within the transaction, inventory is reserved by creating records in an Inventory Hold table, available inventory is reduced, the order record is created, and an Outbox event is written. All of these operations are committed atomically to guarantee consistency and prevent overselling. As soon as the transaction commits successfully, the Order Service immediately returns a success response to the user. The user does not wait for downstream processing such as payment. The Outbox table is monitored through CDC, which publishes events to Kafka. Downstream services such as Payment Service consume these events asynchronously. Once payment processing completes, the Payment Service publishes a success or failure event, and the Order Service updates the order status accordingly. Users can retrieve the latest state through the order history APIs. If payment fails or times out, a background cleanup job scans for expired inventory holds. For each expired hold, inventory is released back to the available pool, the hold record is removed, and the order is marked as failed. This ensures reserved inventory does not remain locked indefinitely. To handle client retries and network failures safely, order creation is protected using idempotency keys. If the same request is received multiple times, the system returns the previously created order instead of creating duplicate reservations or duplicate orders. Overall, the design uses PostgreSQL as the source of truth for orders and inventory, Elasticsearch for low-latency product and geo searches, Redis for caching travel-time calculations, Kafka for asynchronous event propagation, CDC for keeping search indexes synchronized, and inventory reservations to provide strong consistency during ordering while still achieving fast search performance.
Draw your architecture for Food Delivery System and get an instant hire/no-hire signal from 6 specialized AI reviewers — free to start.