├── .circleci
└── config.yml
├── .settings
└── .gitignore
├── README.md
├── all-order-processor
├── .gitignore
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── pl
│ │ └── piomin
│ │ └── services
│ │ └── vertx
│ │ └── order
│ │ ├── AllOrderProcessorVerticle.java
│ │ └── model
│ │ ├── Order.java
│ │ ├── OrderStatus.java
│ │ └── OrderType.java
│ └── resources
│ └── log4j.xml
├── mulpiple-order-processor
├── .gitignore
├── .settings
│ └── .gitignore
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── pl
│ │ └── piomin
│ │ └── services
│ │ └── vertx
│ │ └── order
│ │ ├── MultipleOrderProcessorVerticle.java
│ │ └── model
│ │ ├── Order.java
│ │ ├── OrderStatus.java
│ │ └── OrderType.java
│ └── resources
│ └── log4j.xml
├── order-processor
├── .gitignore
├── .settings
│ └── .gitignore
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── pl
│ │ └── piomin
│ │ └── services
│ │ └── vertx
│ │ └── order
│ │ ├── SingleOrderProcessorVerticle.java
│ │ └── model
│ │ ├── Order.java
│ │ ├── OrderStatus.java
│ │ └── OrderType.java
│ └── resources
│ └── log4j.xml
├── order-service
├── .gitignore
├── .settings
│ └── .gitignore
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── pl
│ │ └── piomin
│ │ └── services
│ │ └── vertx
│ │ └── order
│ │ ├── OrderVerticle.java
│ │ └── model
│ │ ├── Order.java
│ │ ├── OrderStatus.java
│ │ └── OrderType.java
│ └── resources
│ └── log4j.xml
├── pom.xml
└── renovate.json
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 |
3 | jobs:
4 | analyze:
5 | docker:
6 | - image: 'cimg/openjdk:21.0.9'
7 | steps:
8 | - checkout
9 | - run:
10 | name: Analyze on SonarCloud
11 | command: mvn verify sonar:sonar
12 |
13 | executors:
14 | jdk:
15 | docker:
16 | - image: 'cimg/openjdk:21.0.9'
17 |
18 | orbs:
19 | maven: circleci/maven@2.1.1
20 |
21 | workflows:
22 | maven_test:
23 | jobs:
24 | - maven/test:
25 | executor: jdk
26 | verify_dependencies: false
27 | - analyze:
28 | context: SonarCloud
--------------------------------------------------------------------------------
/.settings/.gitignore:
--------------------------------------------------------------------------------
1 | /org.eclipse.core.resources.prefs
2 | /org.eclipse.jdt.core.prefs
3 | /org.eclipse.m2e.core.prefs
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Partitioning with Apache Kafka and Vert.x
2 |
3 | Detailed description can be found here: [Partitioning with Apache Kafka and Vert.x](https://piotrminkowski.com/2018/01/30/partitioning-with-apache-kafka-and-vertx/)
4 |
5 | # Vert.x + Kafka — Order Processing Demo
6 |
7 | A demonstration of using Eclipse Vert.x with Apache Kafka for an order processing pipeline. The `order-service` module exposes a REST endpoint to submit orders, which are sent to a Kafka topic; multiple consumer verticles process orders from different partitions to illustrate ordered and parallel consumption.
8 |
9 | ## 🗂️ Modules
10 | | Path | Description |
11 | |----------------------------|---------------------------------------|
12 | | `order-service` | REST API → produces to **orders-out** |
13 | | `order-processor` | Consumes partition 0 |
14 | | `multiple-order-processor` | Consumes partition 1 |
15 | | `all-order-processor` | Consumes all partitions |
16 |
17 | ## ✅ Prerequisites
18 | - Java 21
19 | - Maven 3.9+
20 | - Running Kafka broker (defaults to `192.168.99.100:9092`)
21 |
22 | ## ⚡ Quick Start
23 | ```bash
24 | # Start Zookeeper (if needed)
25 | docker run -d --name zookeeper -p 2181:2181 zookeeper:3.5
26 |
27 | # Start single-node Kafka
28 | docker run -d --name kafka -p 9092:9092 \
29 | --link zookeeper:zookeeper \
30 | -e KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 \
31 | -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.99.100:9092 \
32 | -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
33 | confluentinc/cp-kafka:latest
34 |
35 | # Build all modules
36 | mvn clean package
37 |
38 | # Run verticles
39 | java -jar order-service/target/order-service-*.jar
40 | java -jar order-processor/target/order-processor-*.jar
41 | java -jar multiple-order-processor/target/multiple-order-processor-*.jar
42 | java -jar all-order-processor/target/all-order-processor-*.jar
43 | ```
44 |
45 | ## 🏗️ Architecture
46 | ```mermaid
47 | flowchart LR
48 | Client --> OS[order-service]
49 | OS -->|JSON order| KT["Kafka
orders-out"]
50 | subgraph Consumers
51 | SOP["order-processor
partition 0"]
52 | MOP["multiple-order-processor
partition 1"]
53 | AOP["all-order-processor
all partitions"]
54 | end
55 | KT --> SOP
56 | KT --> MOP
57 | KT --> AOP
58 | ```
59 |
60 | ## 🔧 Configuration
61 | | Key | Default | How to override |
62 | |----------------------|------------------------|-------------------------------|
63 | | `bootstrap.servers` | `192.168.99.100:9092` | `env KAFKA_BOOTSTRAP_SERVERS` |
64 | | `topic` | `orders-out` | `env KAFKA_TOPIC` |
65 |
66 | ## 🔍 Testing
67 | Consume messages from the `orders-out` topic using the Kafka console consumer:
68 | ```bash
69 | kafka-console-consumer --bootstrap-server 192.168.99.100:9092 \
70 | --topic orders-out --from-beginning
71 | ```
72 |
73 | ## 📜 License
74 | MIT © Piotr Mińkowski
75 |
--------------------------------------------------------------------------------
/all-order-processor/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /.classpath
3 | /.project
4 | /.settings/
5 |
--------------------------------------------------------------------------------
/all-order-processor/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | pl.piomin.services
6 | sample-vertx-kafka-messaging
7 | 1.0-SNAPSHOT
8 |
9 | all-order-processor
10 |
11 |
12 | ${project.artifactId}
13 |
14 |
15 |
16 |
17 | io.vertx
18 | vertx-kafka-client
19 | ${vertx.version}
20 |
21 |
22 |
23 |
24 |
25 |
26 | org.apache.maven.plugins
27 | maven-compiler-plugin
28 | 3.14.1
29 |
30 | ${project.build.sourceEncoding}
31 | ${java.version}
32 | ${java.version}
33 |
34 |
35 |
36 | org.apache.maven.plugins
37 | maven-shade-plugin
38 |
39 |
40 |
41 | shade
42 |
43 |
44 | true
45 |
46 |
48 | pl.piomin.services.vertx.order.AllOrderProcessorVerticle
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/all-order-processor/src/main/java/pl/piomin/services/vertx/order/AllOrderProcessorVerticle.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order;
2 |
3 | import java.util.Properties;
4 |
5 | import org.apache.kafka.clients.consumer.ConsumerConfig;
6 | import org.apache.kafka.common.serialization.StringDeserializer;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import io.vertx.core.AbstractVerticle;
11 | import io.vertx.core.Vertx;
12 | import io.vertx.core.json.Json;
13 | import io.vertx.kafka.client.consumer.KafkaConsumer;
14 | import pl.piomin.services.vertx.order.model.Order;
15 | import pl.piomin.services.vertx.order.model.OrderStatus;
16 |
17 | public class AllOrderProcessorVerticle extends AbstractVerticle {
18 |
19 | private static final Logger LOGGER = LoggerFactory.getLogger(AllOrderProcessorVerticle.class);
20 |
21 | public static void main(String[] args) {
22 | Vertx vertx = Vertx.vertx();
23 | vertx.deployVerticle(new AllOrderProcessorVerticle());
24 | }
25 |
26 | @Override
27 | public void start() throws Exception {
28 | Properties config = new Properties();
29 | config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.99.100:9092");
30 | config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
31 | config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
32 | config.put(ConsumerConfig.GROUP_ID_CONFIG, "all-order");
33 | config.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");
34 | config.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
35 | KafkaConsumer consumer = KafkaConsumer.create(vertx, config);
36 | consumer.subscribe("orders-out", ar -> {
37 | if (ar.succeeded()) {
38 | LOGGER.info("Subscribed");
39 | } else {
40 | LOGGER.error("Could not subscribe: err={}", ar.cause().getMessage());
41 | }
42 | });
43 |
44 | consumer.handler(record -> {
45 | LOGGER.info("Processing: key={}, value={}, partition={}, offset={}", record.key(), record.value(), record.partition(), record.offset());
46 | Order order = Json.decodeValue(record.value(), Order.class);
47 | order.setStatus(OrderStatus.DONE);
48 | LOGGER.info("Order processed: id={}, price={}", order.getId(), order.getPrice());
49 | });
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/all-order-processor/src/main/java/pl/piomin/services/vertx/order/model/Order.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order.model;
2 |
3 | public class Order {
4 |
5 | private Long id;
6 | private OrderType type;
7 | private OrderStatus status;
8 | private int price;
9 | private Long relatedOrderId;
10 |
11 | public Long getId() {
12 | return id;
13 | }
14 |
15 | public void setId(Long id) {
16 | this.id = id;
17 | }
18 |
19 | public OrderType getType() {
20 | return type;
21 | }
22 |
23 | public void setType(OrderType type) {
24 | this.type = type;
25 | }
26 |
27 | public OrderStatus getStatus() {
28 | return status;
29 | }
30 |
31 | public void setStatus(OrderStatus status) {
32 | this.status = status;
33 | }
34 |
35 | public int getPrice() {
36 | return price;
37 | }
38 |
39 | public void setPrice(int price) {
40 | this.price = price;
41 | }
42 |
43 | public Long getRelatedOrderId() {
44 | return relatedOrderId;
45 | }
46 |
47 | public void setRelatedOrderId(Long relatedOrderId) {
48 | this.relatedOrderId = relatedOrderId;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/all-order-processor/src/main/java/pl/piomin/services/vertx/order/model/OrderStatus.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order.model;
2 |
3 | public enum OrderStatus {
4 |
5 | NEW, PROCESSING, DONE, REJECTED;
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/all-order-processor/src/main/java/pl/piomin/services/vertx/order/model/OrderType.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order.model;
2 |
3 | public enum OrderType {
4 |
5 | SINGLE, MULTIPLE;
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/all-order-processor/src/main/resources/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/mulpiple-order-processor/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /.classpath
3 | /.project
4 |
--------------------------------------------------------------------------------
/mulpiple-order-processor/.settings/.gitignore:
--------------------------------------------------------------------------------
1 | /org.eclipse.core.resources.prefs
2 | /org.eclipse.jdt.core.prefs
3 | /org.eclipse.m2e.core.prefs
4 |
--------------------------------------------------------------------------------
/mulpiple-order-processor/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | pl.piomin.services
6 | sample-vertx-kafka-messaging
7 | 1.0-SNAPSHOT
8 |
9 | mulpiple-order-processor
10 |
11 |
12 | ${project.artifactId}
13 |
14 |
15 |
16 |
17 | io.vertx
18 | vertx-kafka-client
19 | ${vertx.version}
20 |
21 |
22 |
23 |
24 |
25 |
26 | org.apache.maven.plugins
27 | maven-compiler-plugin
28 | 3.14.1
29 |
30 | ${project.build.sourceEncoding}
31 | ${java.version}
32 | ${java.version}
33 |
34 |
35 |
36 | org.apache.maven.plugins
37 | maven-shade-plugin
38 |
39 |
40 |
41 | shade
42 |
43 |
44 | true
45 |
46 |
48 | pl.piomin.services.vertx.order.MultipleOrderProcessorVerticle
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/mulpiple-order-processor/src/main/java/pl/piomin/services/vertx/order/MultipleOrderProcessorVerticle.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 | import java.util.Properties;
6 |
7 | import org.apache.kafka.clients.consumer.ConsumerConfig;
8 | import org.apache.kafka.common.serialization.StringDeserializer;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | import io.vertx.core.AbstractVerticle;
13 | import io.vertx.core.Vertx;
14 | import io.vertx.core.json.Json;
15 | import io.vertx.kafka.client.common.TopicPartition;
16 | import io.vertx.kafka.client.consumer.KafkaConsumer;
17 | import pl.piomin.services.vertx.order.model.Order;
18 |
19 | public class MultipleOrderProcessorVerticle extends AbstractVerticle {
20 |
21 | private static final Logger LOGGER = LoggerFactory.getLogger(MultipleOrderProcessorVerticle.class);
22 |
23 | private Map ordersWaiting = new HashMap<>();
24 |
25 | public static void main(String[] args) {
26 | Vertx vertx = Vertx.vertx();
27 | vertx.deployVerticle(new MultipleOrderProcessorVerticle());
28 | }
29 |
30 | @Override
31 | public void start() throws Exception {
32 | Properties config = new Properties();
33 | config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.99.100:9092");
34 | config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
35 | config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
36 | config.put(ConsumerConfig.GROUP_ID_CONFIG, "multiple-order");
37 | config.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");
38 | config.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
39 | TopicPartition tp = new TopicPartition().setPartition(1).setTopic("orders-out");
40 | KafkaConsumer consumer = KafkaConsumer.create(vertx, config);
41 | consumer.assign(tp, ar -> {
42 | if (ar.succeeded()) {
43 | LOGGER.info("Subscribed");
44 | consumer.assignment(done1 -> {
45 | if (done1.succeeded()) {
46 | for (TopicPartition topicPartition : done1.result()) {
47 | LOGGER.info("Partition: topic={}, number={}", topicPartition.getTopic(), topicPartition.getPartition());
48 | }
49 | } else {
50 | LOGGER.error("Could not assign partition: err={}", done1.cause().getMessage());
51 | }
52 | });
53 | } else {
54 | LOGGER.error("Could not subscribe: err={}", ar.cause().getMessage());
55 | }
56 | });
57 |
58 | consumer.handler(record -> {
59 | LOGGER.info("Processing: key={}, value={}, partition={}, offset={}", record.key(), record.value(), record.partition(), record.offset());
60 | Order order = Json.decodeValue(record.value(), Order.class);
61 | if (ordersWaiting.containsKey(record.offset())) {
62 | LOGGER.info("Related order found: id={}, price={}", order.getId(), order.getPrice());
63 | LOGGER.info("Current price: price={}", order.getPrice() + ordersWaiting.get(record.offset()).getPrice());
64 | consumer.seekToEnd(tp);
65 | }
66 |
67 | if (order.getRelatedOrderId() != null && !ordersWaiting.containsKey(order.getRelatedOrderId())) {
68 | ordersWaiting.put(order.getRelatedOrderId(), order);
69 | consumer.seek(tp, order.getRelatedOrderId());
70 | }
71 | });
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/mulpiple-order-processor/src/main/java/pl/piomin/services/vertx/order/model/Order.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order.model;
2 |
3 | public class Order {
4 |
5 | private Long id;
6 | private OrderType type;
7 | private OrderStatus status;
8 | private int price;
9 | private Long relatedOrderId;
10 |
11 | public Long getId() {
12 | return id;
13 | }
14 |
15 | public void setId(Long id) {
16 | this.id = id;
17 | }
18 |
19 | public OrderType getType() {
20 | return type;
21 | }
22 |
23 | public void setType(OrderType type) {
24 | this.type = type;
25 | }
26 |
27 | public OrderStatus getStatus() {
28 | return status;
29 | }
30 |
31 | public void setStatus(OrderStatus status) {
32 | this.status = status;
33 | }
34 |
35 | public int getPrice() {
36 | return price;
37 | }
38 |
39 | public void setPrice(int price) {
40 | this.price = price;
41 | }
42 |
43 | public Long getRelatedOrderId() {
44 | return relatedOrderId;
45 | }
46 |
47 | public void setRelatedOrderId(Long relatedOrderId) {
48 | this.relatedOrderId = relatedOrderId;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/mulpiple-order-processor/src/main/java/pl/piomin/services/vertx/order/model/OrderStatus.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order.model;
2 |
3 | public enum OrderStatus {
4 |
5 | NEW, PROCESSING, DONE, REJECTED;
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/mulpiple-order-processor/src/main/java/pl/piomin/services/vertx/order/model/OrderType.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order.model;
2 |
3 | public enum OrderType {
4 |
5 | SINGLE, MULTIPLE;
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/mulpiple-order-processor/src/main/resources/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/order-processor/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /.classpath
3 | /.project
4 |
--------------------------------------------------------------------------------
/order-processor/.settings/.gitignore:
--------------------------------------------------------------------------------
1 | /org.eclipse.core.resources.prefs
2 | /org.eclipse.jdt.core.prefs
3 | /org.eclipse.m2e.core.prefs
4 |
--------------------------------------------------------------------------------
/order-processor/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | pl.piomin.services
6 | sample-vertx-kafka-messaging
7 | 1.0-SNAPSHOT
8 |
9 | order-processor
10 |
11 |
12 | ${project.artifactId}
13 |
14 |
15 |
16 |
17 | io.vertx
18 | vertx-kafka-client
19 | ${vertx.version}
20 |
21 |
22 |
23 |
24 |
25 |
26 | org.apache.maven.plugins
27 | maven-compiler-plugin
28 | 3.14.1
29 |
30 | ${project.build.sourceEncoding}
31 | ${java.version}
32 | ${java.version}
33 |
34 |
35 |
36 | org.apache.maven.plugins
37 | maven-shade-plugin
38 |
39 |
40 |
41 | shade
42 |
43 |
44 | true
45 |
46 |
48 | pl.piomin.services.vertx.order.SingleOrderProcessorVerticle
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/order-processor/src/main/java/pl/piomin/services/vertx/order/SingleOrderProcessorVerticle.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order;
2 |
3 | import java.util.Properties;
4 |
5 | import org.apache.kafka.clients.consumer.ConsumerConfig;
6 | import org.apache.kafka.common.serialization.StringDeserializer;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import io.vertx.core.AbstractVerticle;
11 | import io.vertx.core.Vertx;
12 | import io.vertx.kafka.client.common.TopicPartition;
13 | import io.vertx.kafka.client.consumer.KafkaConsumer;
14 |
15 | public class SingleOrderProcessorVerticle extends AbstractVerticle {
16 |
17 | private static final Logger LOGGER = LoggerFactory.getLogger(SingleOrderProcessorVerticle.class);
18 |
19 | public static void main(String[] args) {
20 | Vertx vertx = Vertx.vertx();
21 | vertx.deployVerticle(new SingleOrderProcessorVerticle());
22 | }
23 |
24 | @Override
25 | public void start() throws Exception {
26 | Properties config = new Properties();
27 | config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.99.100:9092");
28 | config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
29 | config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
30 | config.put(ConsumerConfig.GROUP_ID_CONFIG, "single-order");
31 | config.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");
32 | config.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
33 | TopicPartition tp = new TopicPartition().setPartition(0).setTopic("orders-out");
34 | KafkaConsumer consumer = KafkaConsumer.create(vertx, config);
35 | consumer.assign(tp, ar -> {
36 | if (ar.succeeded()) {
37 | LOGGER.info("Subscribed");
38 | consumer.assignment(done1 -> {
39 | if (done1.succeeded()) {
40 | for (TopicPartition topicPartition : done1.result()) {
41 | LOGGER.info("Partition: topic={}, number={}", topicPartition.getTopic(), topicPartition.getPartition());
42 | }
43 | }
44 | });
45 | } else {
46 | LOGGER.error("Could not subscribe: err={}", ar.cause().getMessage());
47 | }
48 | });
49 |
50 | consumer.handler(record -> {
51 | LOGGER.info("Processing: key={}, value={}, partition={}, offset={}", record.key(), record.value(), record.partition(), record.offset());
52 | });
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/order-processor/src/main/java/pl/piomin/services/vertx/order/model/Order.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order.model;
2 |
3 | public class Order {
4 |
5 | private Long id;
6 | private OrderType type;
7 | private OrderStatus status;
8 | private int price;
9 |
10 | public Long getId() {
11 | return id;
12 | }
13 |
14 | public void setId(Long id) {
15 | this.id = id;
16 | }
17 |
18 | public OrderType getType() {
19 | return type;
20 | }
21 |
22 | public void setType(OrderType type) {
23 | this.type = type;
24 | }
25 |
26 | public OrderStatus getStatus() {
27 | return status;
28 | }
29 |
30 | public void setStatus(OrderStatus status) {
31 | this.status = status;
32 | }
33 |
34 | public int getPrice() {
35 | return price;
36 | }
37 |
38 | public void setPrice(int price) {
39 | this.price = price;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/order-processor/src/main/java/pl/piomin/services/vertx/order/model/OrderStatus.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order.model;
2 |
3 | public enum OrderStatus {
4 |
5 | NEW, PROCESSING, DONE, REJECTED;
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/order-processor/src/main/java/pl/piomin/services/vertx/order/model/OrderType.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order.model;
2 |
3 | public enum OrderType {
4 |
5 | SINGLE, MULTIPLE;
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/order-processor/src/main/resources/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/order-service/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /.classpath
3 | /.project
4 |
--------------------------------------------------------------------------------
/order-service/.settings/.gitignore:
--------------------------------------------------------------------------------
1 | /org.eclipse.core.resources.prefs
2 | /org.eclipse.jdt.core.prefs
3 | /org.eclipse.m2e.core.prefs
4 |
--------------------------------------------------------------------------------
/order-service/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | pl.piomin.services
6 | sample-vertx-kafka-messaging
7 | 1.0-SNAPSHOT
8 |
9 | order-service
10 |
11 |
12 | ${project.artifactId}
13 |
14 |
15 |
16 |
17 | io.vertx
18 | vertx-kafka-client
19 | ${vertx.version}
20 |
21 |
22 | io.vertx
23 | vertx-web
24 | ${vertx.version}
25 |
26 |
27 |
28 |
29 |
30 |
31 | org.apache.maven.plugins
32 | maven-compiler-plugin
33 | 3.14.1
34 |
35 | ${project.build.sourceEncoding}
36 | ${java.version}
37 | ${java.version}
38 |
39 |
40 |
41 | org.apache.maven.plugins
42 | maven-shade-plugin
43 |
44 |
45 |
46 | shade
47 |
48 |
49 | true
50 |
51 |
53 | pl.piomin.services.vertx.order.OrderVerticle
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/order-service/src/main/java/pl/piomin/services/vertx/order/OrderVerticle.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order;
2 |
3 | import io.vertx.core.AbstractVerticle;
4 | import io.vertx.core.Vertx;
5 | import io.vertx.core.http.HttpMethod;
6 | import io.vertx.core.json.Json;
7 | import io.vertx.core.json.JsonObject;
8 | import io.vertx.ext.web.Router;
9 | import io.vertx.ext.web.handler.BodyHandler;
10 | import io.vertx.ext.web.handler.ResponseContentTypeHandler;
11 | import io.vertx.kafka.client.producer.KafkaProducer;
12 | import io.vertx.kafka.client.producer.KafkaProducerRecord;
13 | import io.vertx.kafka.client.serialization.JsonObjectSerializer;
14 | import org.apache.kafka.clients.producer.ProducerConfig;
15 | import org.apache.kafka.common.serialization.StringSerializer;
16 | import org.slf4j.Logger;
17 | import org.slf4j.LoggerFactory;
18 | import pl.piomin.services.vertx.order.model.Order;
19 | import pl.piomin.services.vertx.order.model.OrderStatus;
20 |
21 | import java.util.Properties;
22 |
23 | public class OrderVerticle extends AbstractVerticle {
24 |
25 | private static final Logger LOGGER = LoggerFactory.getLogger(OrderVerticle.class);
26 |
27 | public static void main(String[] args) {
28 | Vertx vertx = Vertx.vertx();
29 | vertx.deployVerticle(new OrderVerticle());
30 | }
31 |
32 | @Override
33 | public void start() throws Exception {
34 | Properties config = new Properties();
35 | config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.99.100:9092");
36 | config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
37 | config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonObjectSerializer.class);
38 | config.put(ProducerConfig.ACKS_CONFIG, "1");
39 | KafkaProducer producer = KafkaProducer.create(vertx, config);
40 | producer.partitionsFor("orders-out", done -> {
41 | done.result().forEach(p -> LOGGER.info("Partition: id={}, topic={}", p.getPartition(), p.getTopic()));
42 | });
43 |
44 | Router router = Router.router(vertx);
45 | router.route("/order/*").handler(ResponseContentTypeHandler.create());
46 | router.route(HttpMethod.POST, "/order").handler(BodyHandler.create());
47 | router.post("/order").produces("application/json").handler(rc -> {
48 | Order o = Json.decodeValue(rc.getBodyAsString(), Order.class);
49 | KafkaProducerRecord record = KafkaProducerRecord.create("orders-out", null, rc.getBodyAsJson(), o.getType().ordinal());
50 | producer.send(record).onSuccess(recordMetadata -> {
51 | LOGGER.info("Record sent: msg={}, destination={}, partition={}, offset={}", record.value(), recordMetadata.getTopic(), recordMetadata.getPartition(), recordMetadata.getOffset());
52 | o.setId(recordMetadata.getOffset());
53 | o.setStatus(OrderStatus.PROCESSING);
54 | rc.response().end(Json.encodePrettily(o));
55 | }).onFailure(err -> {
56 | Throwable t = err.getCause();
57 | LOGGER.error("Error sent to topic: {}", t.getMessage());
58 | o.setStatus(OrderStatus.REJECTED);
59 | });
60 | });
61 | vertx.createHttpServer().requestHandler(router).listen(8090);
62 |
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/order-service/src/main/java/pl/piomin/services/vertx/order/model/Order.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order.model;
2 |
3 | public class Order {
4 |
5 | private Long id;
6 | private OrderType type;
7 | private OrderStatus status;
8 | private int price;
9 | private Long relatedOrderId;
10 |
11 | public Long getId() {
12 | return id;
13 | }
14 |
15 | public void setId(Long id) {
16 | this.id = id;
17 | }
18 |
19 | public OrderType getType() {
20 | return type;
21 | }
22 |
23 | public void setType(OrderType type) {
24 | this.type = type;
25 | }
26 |
27 | public OrderStatus getStatus() {
28 | return status;
29 | }
30 |
31 | public void setStatus(OrderStatus status) {
32 | this.status = status;
33 | }
34 |
35 | public int getPrice() {
36 | return price;
37 | }
38 |
39 | public void setPrice(int price) {
40 | this.price = price;
41 | }
42 |
43 | public Long getRelatedOrderId() {
44 | return relatedOrderId;
45 | }
46 |
47 | public void setRelatedOrderId(Long relatedOrderId) {
48 | this.relatedOrderId = relatedOrderId;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/order-service/src/main/java/pl/piomin/services/vertx/order/model/OrderStatus.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order.model;
2 |
3 | public enum OrderStatus {
4 |
5 | NEW, PROCESSING, DONE, REJECTED;
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/order-service/src/main/java/pl/piomin/services/vertx/order/model/OrderType.java:
--------------------------------------------------------------------------------
1 | package pl.piomin.services.vertx.order.model;
2 |
3 | public enum OrderType {
4 |
5 | SINGLE, MULTIPLE;
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/order-service/src/main/resources/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | pl.piomin.services
5 | sample-vertx-kafka-messaging
6 | 1.0-SNAPSHOT
7 | pom
8 |
9 |
10 | UTF-8
11 | 21
12 | 4.5.22
13 | piomin_sample-vertx-kafka-messaging
14 | piomin
15 | https://sonarcloud.io
16 |
17 |
18 |
19 | order-service
20 | order-processor
21 | mulpiple-order-processor
22 | all-order-processor
23 |
24 |
25 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "config:base",":dependencyDashboard"
5 | ],
6 | "packageRules": [
7 | {
8 | "matchUpdateTypes": ["minor", "patch", "pin", "digest"],
9 | "automerge": true
10 | }
11 | ],
12 | "prCreation": "not-pending"
13 | }
--------------------------------------------------------------------------------