The goal of this project is to implement a "News" processing pipeline composed of five Spring Boot applications: producer-api, categorizer-service, collector-service, publisher-api and news-client.
-
We are using
Spring Cloud Streamframework for building highly scalable event-driven applications connected with shared messaging systems. -
We are using
Spring Data Elasticsearchto persist data inElasticsearch. -
We are using
Thymeleafas HTML template -
We are using
Zipkinfor visualizing traces between and within applications. -
We are using
Eureka, also known as Discovery Server, it is a service that holds the information about all applications.
|
Note
|
In docker-swarm-environment repository, it is shown how to deploy this project into a cluster of Docker Engines in swarm mode.
|
Spring Boot Web Java application that creates news and pushes news events to producer.news topic in Kafka.
Spring Boot Web Java application that listens to news events in producer.news topic in Kafka, categorizes and pushes them to categorizer.news topic.
Spring Boot Web Java application that listens for news events in categorizer.news topic in Kafka, saves them in Elasticsearch and pushes the news events to collector.news topic.
Spring Boot Web Java application that reads directly from Elasticsearch and exposes a REST API. It doesn’t listen from Kafka.
Spring Boot Web java application that provides a User Interface to see the news. It implements a Websocket that consumes news events from the topic collector.news. So, news are updated on the fly on the main page. Besides, news-client communicates directly with publisher-api whenever search for a specific news or news update are needed.
The Websocket operation is shown in the short gif below. A news is created in producer-api and, immediately, it is shown in news-client.
In a terminal and inside spring-cloud-stream-elasticsearch folder run
./mvnw clean install --projects commons-newsIt will install commons-news-1.0.0.jar in you local Maven repository, so that it can be visible by all services.
In a terminal and inside spring-cloud-stream-elasticsearch folder, in order to build the applications docker images, you can just run the following script
./build-apps.shOr manually run the following ./mvnw commands for each application.
./mvnw clean package dockerfile:build -DskipTests --projects producer-api| Environment Variable | Description |
|---|---|
|
Specify host of the |
|
Specify port of the |
|
Specify host of the |
|
Specify port of the |
|
Specify host of the |
|
Specify port of the |
./mvnw clean package dockerfile:build -DskipTests --projects categorizer-service| Environment Variable | Description |
|---|---|
|
Specify host of the |
|
Specify port of the |
|
Specify host of the |
|
Specify port of the |
|
Specify host of the |
|
Specify port of the |
./mvnw clean package dockerfile:build -DskipTests --projects collector-service| Environment Variable | Description |
|---|---|
|
Specify host of the |
|
Specify nodes port of the |
|
Specify rest port of the |
|
Specify host of the |
|
Specify port of the |
|
Specify host of the |
|
Specify port of the |
|
Specify host of the |
|
Specify port of the |
./mvnw clean package dockerfile:build -DskipTests --projects publisher-api| Environment Variable | Description |
|---|---|
|
Specify host of the |
|
Specify nodes port of the |
|
Specify rest port of the |
|
Specify host of the |
|
Specify port of the |
|
Specify host of the |
|
Specify port of the |
./mvnw clean package dockerfile:build -DskipTests --projects news-client| Environment Variable | Description |
|---|---|
|
Specify host of the |
|
Specify port of the |
|
Specify host of the |
|
Specify port of the |
|
Specify host of the |
|
Specify port of the |
Open a terminal and inside spring-cloud-stream-elasticsearch root folder run
docker-compose up -dWait a until all containers are Up (healthy). You can check their status by running
docker-compose psOpen a terminal and inside spring-cloud-stream-elasticsearch root folder run following script
./start-apps.shDuring development, it is easier to just run the applications instead of always build the docker images and run it. For it, inside spring-cloud-stream-elasticsearch, run the following Maven commands in different terminals
./mvnw spring-boot:run --projects producer-api -Dspring-boot.run.jvmArguments="-Dserver.port=9080"./mvnw spring-boot:run --projects categorizer-service -Dspring-boot.run.jvmArguments="-Dserver.port=9081"./mvnw spring-boot:run --projects collector-service -Dspring-boot.run.jvmArguments="-Dserver.port=9082"./mvnw spring-boot:run --projects publisher-api -Dspring-boot.run.jvmArguments="-Dserver.port=9083"| Application | URL |
|---|---|
producer-api |
|
publisher-api |
|
news-client |
Run the command below to stop the applications
./stop-apps.shThen, run the following command to stop and remove docker-compose containers, networks and volumes
docker-compose down -vEureka can be accessed at http://localhost:8761
Kafka Topics UI can be accessed at http://localhost:8085
Zipkin can be accessed at http://localhost:9411
The figure below shows an example of the complete flow a news passes through. It goes since producer-api, where the news is created, until news-client.
Kafka Manager can be accessed at http://localhost:9000
Configuration
-
First, you must create a new cluster. Click on
Cluster(dropdown on the header) and then onAdd Cluster -
Type the name of your cluster in
Cluster Namefield, for example:MyZooCluster -
Type
zookeeper:2181inCluster Zookeeper Hostsfield -
Enable checkbox
Poll consumer information (Not recommended for large # of consumers) -
Click on
Savebutton at the bottom of the page.
The figure below shows the consumers os the Kafka topics. As we can see, the consumers are updated as the lag is 0
-
add alias to the index: wait for this feature be available in Spring Data Elasticsearch (https://jira.spring.io/browse/DATAES-192)
-
news-client: bug. everytime sync is clicked, it enables Websocket; -
news-client: if websocket is enabled/disabled, sync button should be disabled/enabled; -
news-client: implement pagination;
-
In
news-clientapplication.yml, I needed to set the propertyspring.sleuth.async.enabledtofalseotherwise the Websocket wouldn’t work. I was having the following exception[source] ---- ERROR [news-client,39ba826690e440da,39ba826690e440da,true] 1 --- [nio-8080-exec-2] o.s.c.s.i.web.ExceptionLoggingFilter : Uncaught exception thrown org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.socket.sockjs.SockJsException: Uncaught failure in SockJS request, uri=http://localhost:8080/news-websocket/202/gcbccz4x/websocket; nested exception is org.springframework.web.socket.sockjs.SockJsException: Uncaught failure for request http://localhost:8080/news-websocket/202/gcbccz4x/websocket; nested exception is org.springframework.core.task.TaskRejectedException: Executor [java.util.concurrent.ScheduledThreadPoolExecutor@2427859c[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 1]] did not accept task: org.springframework.cloud.sleuth.instrument.async.TraceRunnable@51841203 ----



