This repository contains a functional example of an order delivery service similar to UberEats, DoorDash, and Instacart.

Overview

Order Delivery Microservice Example

In an event-driven microservices architecture, the concept of a domain event is central to the behavior of each service. Popular practices such as CQRS (Command Query Responsibility Segregation) in combination with Event Sourcing are becoming more common in applications as microservice architectures continue to rise in popularity.

This reference architecture and sample project demonstrates an event-driven microservice architecture that use Spring Boot and Spring Cloud.

Demonstrated concepts:

  • Event Sourcing
  • Event Stream Processing
  • Change Data Capture (CDC)
  • Change Data Analytics
  • Hypermedia Event Logs
  • Real-time Analytics Dashboards

Use cases

This application is a work in progress. The full list of initial requirements are listed below. This application is intended to show a modern microservice architecture that requires real-time analytics and change data capture.

Order Service

API usage information for the order-web service can be found here.

  • Includes an order web service that tracks new order deliveries.
  • Includes a load simulator that realistically simulates a fleet of drivers delivering restaurant orders to customers.
  • Uses a list of real Starbucks restaurants to simulate order life cycles across all locations in the United States.
  • Generates fake delivery locations within 30 miles (ca. 48 km) of each Starbucks.
  • Generates realistic delivery scenarios and simulates supply/demand based on pre-seeded variables for restaurant locations.
  • Generates semi-realistic geospatial updates that tracks the location of an order as it makes its way to a customer’s delivery location.
  • Simulates driver availability based on location and distance from a restaurant location.

Dashboards

  • Real-time geospatial dashboard of current deliveries
    • Show current deliveries by restaurant id
    • Show current deliveries by restaurant city

License

This project is an open source product licensed under Apache License v2.

Comments
  • Clarify structure of order_event table

    Clarify structure of order_event table

    Hey @kbastani, there's still quite a few fields in order_event, which I don't think we need, like restaurant_city, order_location_lat, etc. Or do we need them? The structure currently looks a bit like a mixture of an outbox table (essentially solely an event container) and an actual table for storing purchase orders with all the distinct columns, which is a bit confusing.

    Slightly related: can we make last_modified an actual temporal column type like TIMESTAMP?

    opened by gunnarmorling 4
  • Implement Driver API

    Implement Driver API

    When it comes to an order delivery simulation, there are several resources that are constrained. For example, delivery drivers, perhaps the most important actor in the order delivery process, are constrained in their location and availability. To simulate this properly using a client-side resource scheduler, we need to create a fixed number of drivers around restaurant locations.

    When a simulation is started, new Driver entities are created with geolocation coordinates nearby Restaurant locations. When driver GPS location updates are applied to the Driver domain object, a DriverEvent contains the details of the driver's location and availability to take new orders. When a Restaurant has an order that is ready for pickup, available Drivers within an arbitrary distance should be notified of order availability.

    Current order delivery applications like UberEats provides a single item queue for accepting new driver requests. To implement this, a DriverRequest object should be a property of the Driver entity. A DriverRequest will remain actively available to accept unless another Driver accepts the request before others. The client-side workflow for this will drive the state of DriverRequest in a polling state (application checks for new requests when old requests are no longer available).

    To push a DriverRequest to a Driver, an API should be implemented that queries the closest Restaurant where an Order is ready for pickup. This URL could be a command on the Driver API at /v1/drivers/{driverId}/commands/requestDelivery.

    If the Driver is in a valid state, the action will search for the closest available Order within a minimum distance. Since this requires geospatial search, Apache Pinot will be used from the order-delivery-service to find available order requests. Since the GPS coordinates of a Driver are available within the context of the requestDelivery command, a geospatial search will select the available orders using Pinot. Because the Pinot query will have eventually consistent data, the requestDelivery action will be sure to check the current state of an Order in MySQL.

    • [x] #12
    • [x] #13
    • [x] #14
    • [x] Implement DriverRequest notifications
    • [x] #15
    • [x] #17
    opened by kbastani 2
  • WIP Adding outbox connector

    WIP Adding outbox connector

    Hey @kbastani, some WIP here. I still need to look into "un-stringifying" this, but I'm blocked by https://github.com/kbastani/order-delivery-microservice-example/issues/4; the order service is mostly unresponsive and requests to place an order will time out. Eventually, the service dies with OOME. I'm not sure what it's doing 🤔 . Some notes on the current status:

    • Messages are sent to the outbox.event.Order topic atm., but we can adjust that (the Order suffix is the value of a new aggregate_type column I added); any other preferences for the prefix? Could also just be Order, if you want.
    • The current structure is like this:
    {"schema":{"type":"string","optional":true},"payload":"{\"createdAt\":1624632622667,\"lastModified\":1624632622667,\"status\":\"ORDER_CREATED\",\"accountId\":1234,\"links\":[],\"orderId\":53}"}
    

    I'll remove the schema part, making it that:

    "{\"createdAt\":1624632622667,\"lastModified\":1624632622667,\"status\":\"ORDER_CREATED\",\"accountId\":1234,\"links\":[],\"orderId\":53}"
    

    Finally, I'll unstringify it, making it that:

    { "createdAt" : 1624632622667, "lastModified" : 1624632622667, "status" : "ORDER_CREATED", "accountId" : 1234, "links":[], "orderId":53}
    
    opened by gunnarmorling 2
  • Support Java 16

    Support Java 16

    Java 16 is the current stable version, but the build fails due to some access restriction around Lombok (I suppose caused by the fact that --illegal-access=deny is the default starting with 16. A version update of Lombok might suffice potentially.

    opened by gunnarmorling 2
  • Configuring outbox connector;

    Configuring outbox connector;

    The "Expand JSON SMT" (https://github.com/RedHatInsights/expandjsonsmt/) is used for un-stringifying the outbox event payload. As this SMT only works for specific fields and not the entire message (see https://github.com/RedHatInsights/expandjsonsmt/issues/10), the payload is first hoisted into a temporary field, then un-stringified and finally promoted to the top level of the Kafka message value again.

    Hey @kbastani, this gives a nice event structure finally:

    {"createdAt":1624638360969,"lastModified":1624638371355,"status":"ORDER_ASSIGNED","accountId":62941725,"restaurant":{"id":4,"storeId":7946,"name":"California & Battery","city":"San Francisco","country":"US","latitude":37.793060302734375,"longitude":-122.3997573852539},"links":[],"orderId":976}
    

    The topic is debezium.Order now. I think you can consume that data and sink it into Pinot now? Or is anything else needed for doing so?

    opened by gunnarmorling 1
  • Order service eating up all CPU

    Order service eating up all CPU

    When starting the order service without the load simulator even, it seems to be stuck in some busy loop:

    CONTAINER ID   NAME                                                           CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O        PIDS
    527c77df49b3   festive_brahmagupta                                            0.00%     28.46MiB / 7.775GiB   0.36%     8.26kB / 3.72kB   1.86MB / 0B      1
    c93122ea001b   order-delivery-microservice-example_connect_1                  0.57%     970.3MiB / 7.775GiB   12.19%    1.14MB / 991kB    85.1MB / 106kB   43
    c714f9ec6295   order-delivery-microservice-example_order-delivery-service_1   567.19%   2.323GiB / 7.775GiB   29.88%    36.4MB / 23.9MB   8.19kB / 86kB    35
    dbf55ad8cfec   order-delivery-microservice-example_kafka_1                    1.39%     408.9MiB / 7.775GiB   5.14%     1.08MB / 1.25MB   22MB / 1.24MB    76
    083867bef502   order-delivery-microservice-example_mysql_1                    0.10%     1.989GiB / 7.775GiB   25.58%    23.9MB / 36.4MB   47MB / 317MB     6341
    796775e19440   order-delivery-microservice-example_zookeeper_1                0.06%     92.39MiB / 7.775GiB   1.16%     103kB / 85.2kB    49.9MB / 659kB   52
    
    opened by gunnarmorling 1
  • add statement to initially create db_data volume

    add statement to initially create db_data volume

    When running the heavy mode from scratch, compose immediately complains about missing (external) volume "db_data". The Readme can be extended to add this step.

    opened by tonit 0
  • Adding Debezium

    Adding Debezium

    Hey @kbastani, as discussed here's a PR for adding Debezium to the demo. This currently captures all the tables from the orderweb application, whereas eventually, it should only capture the outbox table.

    Are you going to change the application so that it writes the events into such table, instead of directly writing to Kafka? If so, I then could update the Debezium configuration, so to read from that outbox table exclusively. Ideally, the outbox table would have a schema as described here. Then the outbox routing SMT in Debezium could pretty much be used as-is. No problem if not though (if you prefer other column names for instance), just let me know and I can configure things as needed.

    opened by gunnarmorling 0
Owner
Kenny Bastani
Apache Pinot. Highly scalable hello world examples based on production experiences.
Kenny Bastani
A template and introduction for the first kafka stream application. The readme file contains all the required commands to run the Kafka cluster from Scrach

Kafka Streams Template Maven Project This project will be used to create the followings: A Kafka Producer Application that will start producing random

null 2 Jan 10, 2022
A JVM library to use RabbitMQ as an embedded service

Embedded RabbitMQ Compatibility: Builds: Linux OS X Windows Reports: Dist: Social: This library allows for the use of various RabbitMQ versions as if

Alejandro Rivera 88 Dec 25, 2021
An example Twitch.tv bot that allows you to manage channel rewards (without requiring a message), and chat messages.

Twitch Bot Example shit code that can be used as a template for a twitch bot that takes advantage of channel rewards (that dont require text input) an

Evan 3 Nov 3, 2022
Kafka example - a simple producer and consumer for kafka using spring boot + java

Kafka example - a simple producer and consumer for kafka using spring boot + java

arturcampos 1 Feb 18, 2022
Evgeniy Khyst 54 Dec 28, 2022
EventStoreDB is the database for Event Sourcing. This repository provides a sample of event sourced system that uses EventStoreDB as event store.

Event Sourcing with EventStoreDB Introduction Example Domain Event Sourcing and CQRS 101 State-Oriented Persistence Event Sourcing CQRS Advantages of

Evgeniy Khyst 53 Dec 15, 2022
A modular and portable open source XMPP client library written in Java for Android and Java (SE) VMs

Smack About Smack is an open source, highly modular, easy to use, XMPP client library written in Java for Java SE compatible JVMs and Android. A pure

Ignite Realtime 2.3k Dec 28, 2022
Microservice-based online payment system for customers and merchants using RESTful APIs and message queues

Microservice-based online payment system for customers and merchants using RESTful APIs and message queues

Daniel Larsen 1 Mar 23, 2022
gMark: a domain- and query language-independent graph instance and query workload generator

gMark is a domain- and query language-independent graph instance and query workload generator.

Roan 3 Nov 19, 2022
Efficient reliable UDP unicast, UDP multicast, and IPC message transport

Aeron Efficient reliable UDP unicast, UDP multicast, and IPC message transport. Java and C++ clients are available in this repository, and a .NET clie

Real Logic 6.3k Jan 9, 2023
Event bus for Android and Java that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.

EventBus EventBus is a publish/subscribe event bus for Android and Java. EventBus... simplifies the communication between components decouples event s

Markus Junginger 24.2k Jan 3, 2023
Apache Camel is an open source integration framework that empowers you to quickly and easily integrate various systems consuming or producing data.

Apache Camel Apache Camel is a powerful, open-source integration framework based on prevalent Enterprise Integration Patterns with powerful bean integ

The Apache Software Foundation 4.7k Dec 31, 2022
Powerful event-bus optimized for high throughput in multi-threaded applications. Features: Sync and Async event publication, weak/strong references, event filtering, annotation driven

MBassador MBassador is a light-weight, high-performance event bus implementing the publish subscribe pattern. It is designed for ease of use and aims

Benjamin Diedrichsen 930 Jan 6, 2023
Fast and reliable message broker built on top of Kafka.

Hermes Hermes is an asynchronous message broker built on top of Kafka. We provide reliable, fault tolerant REST interface for message publishing and a

Allegro Tech 742 Jan 3, 2023
Dataflow template which read data from Kafka (Support SSL), transform, and outputs the resulting records to BigQuery

Kafka to BigQuery Dataflow Template The pipeline template read data from Kafka (Support SSL), transform the data and outputs the resulting records to

DoiT International 12 Jun 1, 2021
A Minecraft mod that extends Diet. It rebalances food stats and gives subtle perks for different food groups.

------------------------------------------- Source installation information for modders ------------------------------------------- This code follows

null 9 Mar 8, 2022
Tiny and fast event dispatcher.

HookDispatcher - Tiny and fast event dispatcher. Installation Gradle repositories { maven { url 'https://jitpack.io' } } dependencies { imple

null 8 Dec 7, 2021
This is a very lightweight plugin for Velocity proxy. Have functions including tabList, pingList and global chat.

Essential-PlayerInfo This repo had been transported to our team, and will not be updated here. https://github.com/Team-Jackdaw/Essential-PlayerInfo In

Jonathan Hsu 2 Mar 4, 2022
SeaTunnel is a distributed, high-performance data integration platform for the synchronization and transformation of massive data (offline & real-time).

SeaTunnel SeaTunnel was formerly named Waterdrop , and renamed SeaTunnel since October 12, 2021. SeaTunnel is a very easy-to-use ultra-high-performanc

The Apache Software Foundation 4.4k Jan 2, 2023