[BAEL-5631] Quarkus vs Spring boot improvements (#12520)
* Initial impl * Update framework versions testing from jm to wrk * Add hyperfoil * Add hyperfoil read me
This commit is contained in:
parent
d0ba47e75d
commit
a313c855d3
|
@ -6,6 +6,9 @@ To follow this tutorial, you will need the following things:
|
|||
- Maven (Embedded, IDE, or local installation)
|
||||
- Docker (https://www.docker.com/)
|
||||
- Jmeter (https://jmeter.apache.org/)
|
||||
- wrk (https://github.com/wg/wrk)
|
||||
- hyperfoil (https://hyperfoil.io/)
|
||||
- lua (https://www.lua.org/)
|
||||
|
||||
To create this test, I used some custom features from Jmeter. You can install the Jmeter plugin manager here:
|
||||
https://loadium.com/blog/how-to-install-use-jmeter-plugin. After that, please install the following plugins:
|
||||
|
@ -17,31 +20,32 @@ The test file is `load_test.jmx` in case of any change need. You can open it wit
|
|||
$jmeter_home/bin/jmeter -n -t load_test.jmx -l log.csv -e -o ./report
|
||||
```
|
||||
|
||||
Just remember to change the variable `jmeter_home` with the path to the JMeter folder. The path to the data files is relative, so either keep them in the same folder as the test or use Jmeter GUI to change it.
|
||||
Just remember to change the variable `jmeter_home` with the path to the JMeter folder. The path to the data files is relative, so either keep them in the same folder as the test or use Jmeter GUI to change it. Rememeber that as mentioned in the article, we cannot consider the response times recorded by Jmeter due to the Coordinated Omission Problem.
|
||||
|
||||
Open the VisualVM application and select your application to start monitoring before running the test, and of course, start the sample application first.
|
||||
|
||||
## Spring Boot
|
||||
To build the application, you only need to run the following command in the Spring project root:
|
||||
```
|
||||
./mvnw package -f pom.xml
|
||||
./mvnw clean package -f pom.xml
|
||||
```
|
||||
Or this one in case you want to build the native one:
|
||||
```
|
||||
./mvnw -DskipTests package -Pnative -f pom.xml
|
||||
./mvnw clean package -Pnative -f pom.xml
|
||||
```
|
||||
In this case, you will need to have the `GRAALVM_HOME` env variable defined. You only need this if you want to build the image locally. Otherwise, you can build it using docker by leveraging the Spring Boot maven plugin. It will pull a docker image of the GraalVM, and with that, it will create the native image of the app. To do that, run:
|
||||
```
|
||||
./mvnw spring-boot:build-image
|
||||
./mvnw clean package spring-boot:build-image -Pnative -f pom.xml
|
||||
```
|
||||
You can also create a docker image with the JVM version of the app running the script `build_jvm_docker.sh` or:
|
||||
You can also create a docker image with the JVM version one of the app running the script `build.sh` or:
|
||||
```
|
||||
docker build -f src/main/docker/Dockerfile.jvm -t spring-project:0.1-SNAPSHOT .
|
||||
./mvnw clean package spring-boot:build-image -f pom.xml
|
||||
|
||||
```
|
||||
|
||||
You can execute the script `start_app.sh` or `start_jvm.sh` to run the application locally. In this case, you will need the Postgres DB. You can run it in docker with the command:
|
||||
You can execute the script `start_app.sh` or `start_jvm.sh` to run the application locally. In this case, you will need the Mysql DB. You can run it in docker with the command:
|
||||
```
|
||||
docker run -e POSTGRES_PASSWORD=example -p 5432:5432 postgres
|
||||
docker run --name mysqldb --network=host -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=baeldung -d mysql:5.7.38 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
```
|
||||
You can also run both application and DB from docker, using:
|
||||
```
|
||||
|
@ -67,7 +71,7 @@ And to the JVM version:
|
|||
|
||||
To start the application locally, use either the scripts `start_app.sh` and `start_jvm.sh` with the docker DB:
|
||||
```
|
||||
docker run -e POSTGRES_PASSWORD=example -p 5432:5432 postgres
|
||||
docker run --name mysqldb --network=host -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=baeldung -d mysql:5.7.38 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
```
|
||||
Or use the script to build the docker image of the application, running:
|
||||
```bash
|
||||
|
@ -94,6 +98,38 @@ docker-compose -f src/main/docker/quarkus.yml up
|
|||
|
||||
Now you have all you need to reproduce the tests with your machine.
|
||||
|
||||
## Wrk
|
||||
Another option to execute the load test is to use the wrk. This library is capable of generation a pretty high load only using a single core. To install it you only have to checkout the project compile it (using make) and define the `wrk_home` envvar. To run the test use:
|
||||
|
||||
```
|
||||
./run_test_wrk.sh
|
||||
```
|
||||
You will need to have installed lua in your machine.
|
||||
|
||||
### Tips
|
||||
If you want to run the applications in your machine you can use the following command to restrict the CPUs available to the app:
|
||||
|
||||
```
|
||||
cpulimit -l 300 -p ## 300 means at most 3 cores.
|
||||
```
|
||||
|
||||
This will make sure the load is on the application and not in the DB.
|
||||
## Hyperfoil
|
||||
|
||||
To the hyperfoil test to get a report regarding the performance of the application, its throughput and response time. You can run the `docker_run.sh` from the hyperfoil folder, or the following:
|
||||
|
||||
```
|
||||
docker run -it -v volume:/benchmarks:Z -v tmp/reports:/tmp/reports:Z --network=host quay.io/hyperfoil/hyperfoil cli
|
||||
```
|
||||
And then:
|
||||
```
|
||||
start-local && upload /benchmarks/benchmark.hf.yaml && run benchmark
|
||||
```
|
||||
Optionally, we can extract a html report from it, by running:
|
||||
```
|
||||
report --destination=/tmp/reports
|
||||
```
|
||||
|
||||
### Relevant Articles:
|
||||
|
||||
- [Spring Boot vs Quarkus](https://www.baeldung.com/spring-boot-vs-quarkus)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
|
||||
|
||||
docker run -it -v $SCRIPTPATH/volume:/benchmarks:Z -v $SCRIPTPATH/tmp/reports:/tmp/reports:Z --network=host quay.io/hyperfoil/hyperfoil cli
|
||||
|
||||
#start-local && upload /benchmarks/benchmark.hf.yaml && run benchmark
|
||||
|
||||
# step 1 run: start-local
|
||||
# step 2 run (Run this every time the file is modified): upload /benchmarks/benchmark.hf.yaml
|
||||
# step 3 run: run benchmark
|
||||
# step 4 run: stats
|
||||
# step 5 run: report --destination=/tmp/reports
|
|
@ -0,0 +1,86 @@
|
|||
name: benchmark
|
||||
http:
|
||||
host: http://localhost:8080
|
||||
sharedConnections: 100
|
||||
phases:
|
||||
- main:
|
||||
constantRate:
|
||||
startAfter: rampup
|
||||
usersPerSec: 3300
|
||||
maxSessions: 6000
|
||||
duration: 5m
|
||||
forks:
|
||||
- post_zipcode: &post_zipcode
|
||||
scenario:
|
||||
- fetchIndex:
|
||||
- randomCsvRow:
|
||||
file: /benchmarks/zip_code_database.csv
|
||||
removeQuotes: true
|
||||
columns:
|
||||
0: zip
|
||||
1: type
|
||||
3: city
|
||||
6: state
|
||||
7: county
|
||||
8: timezone
|
||||
- httpRequest:
|
||||
sla:
|
||||
- blockedRatio: 500
|
||||
POST: /zipcode
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
Accept: application/json
|
||||
body: |
|
||||
{
|
||||
"zip" : "${zip}",
|
||||
"type" : "${type}",
|
||||
"city" : "${city}",
|
||||
"state" : "${state}",
|
||||
"county" : "${county}",
|
||||
"timezone" : "${timezone}"
|
||||
}
|
||||
- get_zipcode: &get_zipcode
|
||||
scenario:
|
||||
- fetchIndex:
|
||||
- randomCsvRow:
|
||||
file: /benchmarks/zip_code_database.csv
|
||||
removeQuotes: true
|
||||
columns:
|
||||
0: zipcode
|
||||
- httpRequest:
|
||||
sla:
|
||||
- blockedRatio: 500
|
||||
headers:
|
||||
accept: application/json
|
||||
GET: /zipcode/${zipcode}
|
||||
- get_zipcode_by_city: &get_zipcode_by_city
|
||||
scenario:
|
||||
- fetchDetails:
|
||||
- randomCsvRow:
|
||||
file: /benchmarks/cities.csv
|
||||
removeQuotes: true
|
||||
columns:
|
||||
0: city
|
||||
- httpRequest:
|
||||
sla:
|
||||
- blockedRatio: 500
|
||||
headers:
|
||||
accept: application/json
|
||||
GET: /zipcode/by_city?city=${city}
|
||||
- spike:
|
||||
constantRate:
|
||||
startAfter: main
|
||||
usersPerSec: 4400
|
||||
duration: 2m
|
||||
forks:
|
||||
- get_zipcode_by_city: *get_zipcode_by_city
|
||||
- get_zipcode: *get_zipcode
|
||||
|
||||
- rampup:
|
||||
increasingRate:
|
||||
initialUsersPerSec: 3
|
||||
targetUsersPerSec: 2500
|
||||
duration: 1m
|
||||
forks:
|
||||
- post_zipcode: *post_zipcode
|
||||
- get_zipcode: *get_zipcode
|
|
@ -0,0 +1,136 @@
|
|||
Holtsville
|
||||
Adjuntas
|
||||
Aguada
|
||||
Aguadilla
|
||||
Maricao
|
||||
Anasco
|
||||
Angeles
|
||||
Arecibo
|
||||
Bajadero
|
||||
Barceloneta
|
||||
Boqueron
|
||||
Cabo Rojo
|
||||
Penuelas
|
||||
Camuy
|
||||
Castaner
|
||||
Rosario
|
||||
Sabana Grande
|
||||
Ciales
|
||||
Utuado
|
||||
Dorado
|
||||
Ensenada
|
||||
Florida
|
||||
Garrochales
|
||||
Guanica
|
||||
Guayanilla
|
||||
Hatillo
|
||||
Hormigueros
|
||||
Isabela
|
||||
Jayuya
|
||||
Lajas
|
||||
Lares
|
||||
Las Marias
|
||||
Manati
|
||||
Moca
|
||||
Rincon
|
||||
Quebradillas
|
||||
Mayaguez
|
||||
San German
|
||||
San Sebastian
|
||||
Morovis
|
||||
Sabana Hoyos
|
||||
San Antonio
|
||||
Vega Alta
|
||||
Vega Baja
|
||||
Yauco
|
||||
Aguas Buenas
|
||||
Aguirre
|
||||
Aibonito
|
||||
Maunabo
|
||||
Arroyo
|
||||
Mercedita
|
||||
Ponce
|
||||
Naguabo
|
||||
Naranjito
|
||||
Orocovis
|
||||
Palmer
|
||||
Patillas
|
||||
Caguas
|
||||
Canovanas
|
||||
Ceiba
|
||||
Cayey
|
||||
Fajardo
|
||||
Cidra
|
||||
Puerto Real
|
||||
Punta Santiago
|
||||
Roosevelt Roads
|
||||
Rio Blanco
|
||||
Rio Grande
|
||||
Salinas
|
||||
San Lorenzo
|
||||
Santa Isabel
|
||||
Vieques
|
||||
Villalba
|
||||
Yabucoa
|
||||
Coamo
|
||||
Las Piedras
|
||||
Loiza
|
||||
Luquillo
|
||||
Culebra
|
||||
Juncos
|
||||
Gurabo
|
||||
Coto Laurel
|
||||
Comerio
|
||||
Corozal
|
||||
Guayama
|
||||
La Plata
|
||||
Humacao
|
||||
Barranquitas
|
||||
Juana Diaz
|
||||
St Thomas
|
||||
Christiansted
|
||||
St John
|
||||
Frederiksted
|
||||
Kingshill
|
||||
San Juan
|
||||
Fort Buchanan
|
||||
Toa Baja
|
||||
Sabana Seca
|
||||
Toa Alta
|
||||
Bayamon
|
||||
Catano
|
||||
Guaynabo
|
||||
Trujillo Alto
|
||||
Saint Just
|
||||
Carolina
|
||||
Agawam
|
||||
Amherst
|
||||
Barre
|
||||
Belchertown
|
||||
Blandford
|
||||
Bondsville
|
||||
Brimfield
|
||||
Chester
|
||||
Chesterfield
|
||||
Chicopee
|
||||
Cummington
|
||||
Easthampton
|
||||
East Longmeadow
|
||||
East Otis
|
||||
Feeding Hills
|
||||
Gilbertville
|
||||
Goshen
|
||||
Granby
|
||||
Granville
|
||||
Hadley
|
||||
Hampden
|
||||
Hardwick
|
||||
Hatfield
|
||||
Haydenville
|
||||
Holyoke
|
||||
Huntington
|
||||
Leeds
|
||||
Leverett
|
||||
Ludlow
|
||||
Monson
|
||||
North Amherst
|
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
|
||||
|
||||
./mvnw quarkus:add-extension -Dextensions=container-image-docker
|
||||
mvn quarkus:add-extension -Dextensions=container-image-docker
|
||||
|
||||
if [ "$1" = "native" ]; then
|
||||
./mvnw package -Pnative -Dquarkus.native.container-build=true -f $SCRIPTPATH/pom.xml &&
|
||||
mvn clean package -Pnative -Dquarkus.native.container-build=true -f $SCRIPTPATH/pom.xml &&
|
||||
docker build -f $SCRIPTPATH/src/main/docker/Dockerfile.native -t quarkus-project:0.1-SNAPSHOT $SCRIPTPATH/.
|
||||
elif [ "$1" = "local-native" ]; then
|
||||
mvn clean package -DskipTests -Pnative -f $SCRIPTPATH/pom.xml
|
||||
else
|
||||
./mvnw package -Dquarkus.container-build=true -f $SCRIPTPATH/pom.xml &&
|
||||
mvn clean package -Dquarkus.container-build=true -f $SCRIPTPATH/pom.xml &&
|
||||
docker build -f $SCRIPTPATH/src/main/docker/Dockerfile.jvm -t quarkus-project:0.1-SNAPSHOT $SCRIPTPATH/.
|
||||
fi
|
|
@ -1,150 +1,143 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>quarkus-project</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>quarkus-vs-springboot</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${quarkus.platform.group-id}</groupId>
|
||||
<artifactId>${quarkus.platform.artifact-id}</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>quarkus-vs-springboot</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>quarkus-project</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<properties>
|
||||
<compiler-plugin.version>3.10.1</compiler-plugin.version>
|
||||
<maven.compiler.parameters>true</maven.compiler.parameters>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
|
||||
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
|
||||
<quarkus.platform.version>2.9.2.Final</quarkus.platform.version>
|
||||
<surefire-plugin.version>3.0.0-M6</surefire-plugin.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-hibernate-reactive-panache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-resteasy-reactive</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-reactive-pg-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-arc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-container-image-docker</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${quarkus.platform.group-id}</groupId>
|
||||
<artifactId>${quarkus.platform.artifact-id}</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-hibernate-reactive-panache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-resteasy-reactive</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-reactive-mysql-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-arc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-container-image-docker</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>${quarkus.platform.group-id}</groupId>
|
||||
<artifactId>quarkus-maven-plugin</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
<goal>generate-code</goal>
|
||||
<goal>generate-code-tests</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<parameters>${maven.compiler.parameters}</parameters>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${surefire-plugin.version}</version>
|
||||
<configuration>
|
||||
<useSystemClassLoader>false</useSystemClassLoader>
|
||||
<systemPropertyVariables>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>native</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>native</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>${quarkus.platform.group-id}</groupId>
|
||||
<artifactId>quarkus-maven-plugin</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
<goal>generate-code</goal>
|
||||
<goal>generate-code-tests</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${compiler-plugin.version}</version>
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>${surefire-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<parameters>${maven.compiler.parameters}</parameters>
|
||||
<systemPropertyVariables>
|
||||
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${surefire-plugin.version}</version>
|
||||
<configuration>
|
||||
<useSystemClassLoader>false</useSystemClassLoader>
|
||||
<systemPropertyVariables>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>native</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>native</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>${surefire-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<properties>
|
||||
<quarkus.native.additional-build-args>-H:+AllowVMInspection</quarkus.native.additional-build-args>
|
||||
<quarkus.package.type>native</quarkus.package.type>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<properties>
|
||||
<compiler-plugin.version>3.8.1</compiler-plugin.version>
|
||||
<maven.compiler.parameters>true</maven.compiler.parameters>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
|
||||
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
|
||||
<quarkus.platform.version>2.2.2.Final</quarkus.platform.version>
|
||||
<surefire-plugin.version>3.0.0-M4</surefire-plugin.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
</build>
|
||||
<properties>
|
||||
<quarkus.native.additional-build-args>-H:+AllowVMInspection</quarkus.native.additional-build-args>
|
||||
<quarkus.package.type>native</quarkus.package.type>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
|
|
@ -41,7 +41,8 @@ RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
|
|||
&& echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/conf/security/java.security
|
||||
|
||||
# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
|
||||
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
|
||||
ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.port=5000 -Dcom.sun.management.jmxremote.rmi.port=5001 -Dcom.sun.management.jmxremote.host=0.0.0.0 -Djava.rmi.server.hostname=0.0.0.0"
|
||||
|
||||
# We make four distinct layers so if there are application changes the library layers can be re-used
|
||||
COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/
|
||||
COPY --chown=1001 target/quarkus-app/*.jar /deployments/
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
version: '3.1'
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres
|
||||
image: mysql:5.7.38
|
||||
ports:
|
||||
- '5432:5432'
|
||||
- '3306:3306'
|
||||
environment:
|
||||
POSTGRES_PASSWORD: example
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: baeldung
|
||||
command: [ 'mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci' ]
|
||||
healthcheck:
|
||||
test: mysqladmin ping -h 127.0.0.1 -u $$MYSQL_USER --password=$$MYSQL_PASSWORD
|
||||
app:
|
||||
image: quarkus-project:0.1-SNAPSHOT
|
||||
ports:
|
||||
- '8080:8080'
|
||||
network_mode: "host"
|
||||
environment:
|
||||
DB_URL: postgresql://db:5432/postgres
|
||||
links:
|
||||
- "db"
|
||||
DB_URL: mysql://localhost:3306/baeldung?useSSL=true&requireSSL=true
|
||||
HOST_HOSTNAME: ${EXTERNAL_IP}
|
||||
depends_on:
|
||||
- "db"
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
|
||||
db:
|
||||
condition: service_healthy
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '3.00'
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.baeldung.quarkus_project;
|
||||
|
||||
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
|
||||
import io.quarkus.hibernate.reactive.panache.common.runtime.ReactiveTransactional;
|
||||
import io.smallrye.mutiny.Multi;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
|
||||
|
@ -13,7 +14,8 @@ public class ZipCodeRepo implements PanacheRepositoryBase<ZipCode, String> {
|
|||
return find("city = ?1", city).stream();
|
||||
}
|
||||
|
||||
@ReactiveTransactional
|
||||
public Uni<ZipCode> save(ZipCode zipCode) {
|
||||
return zipCode.persistAndFlush();
|
||||
return zipCode.persist();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,8 @@ package com.baeldung.quarkus_project;
|
|||
|
||||
import io.smallrye.mutiny.Multi;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
|
@ -22,7 +21,7 @@ public class ZipCodeResource {
|
|||
@GET
|
||||
@Path("/{zipcode}")
|
||||
public Uni<ZipCode> findById(@PathParam("zipcode") String zipcode) {
|
||||
return zipRepo.findById(zipcode);
|
||||
return getById(zipcode);
|
||||
}
|
||||
|
||||
@GET
|
||||
|
@ -32,12 +31,17 @@ public class ZipCodeResource {
|
|||
}
|
||||
|
||||
@POST
|
||||
@Transactional
|
||||
public Uni<ZipCode> create(ZipCode zipCode) {
|
||||
return zipRepo.findById(zipCode.getZip())
|
||||
return getById(zipCode.getZip())
|
||||
.onItem()
|
||||
.ifNull()
|
||||
.switchTo(createZipCode(zipCode));
|
||||
.switchTo(createZipCode(zipCode))
|
||||
.onFailure(PersistenceException.class)
|
||||
.recoverWithUni(() -> getById(zipCode.getZip()));
|
||||
}
|
||||
|
||||
private Uni<ZipCode> getById(String zipCode) {
|
||||
return zipRepo.findById(zipCode);
|
||||
}
|
||||
|
||||
private Uni<ZipCode> createZipCode(ZipCode zipCode) {
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
quarkus.datasource.db-kind=postgresql
|
||||
quarkus.datasource.username=postgres
|
||||
quarkus.datasource.password=example
|
||||
quarkus.datasource.db-kind=mysql
|
||||
quarkus.datasource.username=root
|
||||
quarkus.datasource.password=root
|
||||
|
||||
quarkus.datasource.reactive.url=${DB_URL:postgresql://localhost:5432/postgres}
|
||||
quarkus.datasource.reactive.max-size=20
|
||||
quarkus.datasource.reactive.url=${DB_URL:mysql://localhost:3306/baeldung?useSSL=true&requireSSL=true}
|
||||
quarkus.datasource.reactive.max-size=95
|
||||
quarkus.datasource.reactive.mysql.ssl-mode=required
|
||||
|
||||
#quarkus.hibernate-orm.log.sql=true
|
||||
quarkus.hibernate-orm.database.generation=drop-and-create
|
||||
quarkus.native.enable-vm-inspection=true
|
||||
quarkus.datasource.reactive.trust-all=true
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
|
||||
|
||||
if [ "$1" = "native" ]; then
|
||||
mvn clean package -DskipTests spring-boot:build-image -Pnative -f $SCRIPTPATH/pom.xml
|
||||
elif [ "$1" = "local-native" ]; then
|
||||
mvn clean package -DskipTests -Plocal-native -f $SCRIPTPATH/pom.xml
|
||||
else
|
||||
mvn clean package -DskipTests spring-boot:build-image -f $SCRIPTPATH/pom.xml
|
||||
fi
|
|
@ -1,6 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
|
||||
|
||||
docker build -f $SCRIPTPATH/src/main/docker/Dockerfile.jvm -t spring-project:0.1-SNAPSHOT $SCRIPTPATH/.
|
||||
|
|
@ -10,8 +10,8 @@
|
|||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.6.0</version>
|
||||
<relativePath />
|
||||
<version>2.6.9</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@ -29,14 +29,9 @@
|
|||
<version>${spring-native.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.r2dbc</groupId>
|
||||
<artifactId>r2dbc-postgresql</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<groupId>com.github.jasync-sql</groupId>
|
||||
<artifactId>jasync-r2dbc-mysql</artifactId>
|
||||
<version>2.0.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
@ -48,131 +43,210 @@
|
|||
<artifactId>reactor-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>r2dbc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>mysql</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers-bom</artifactId>
|
||||
<version>1.17.2</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<classifier>${repackage.classifier}</classifier>
|
||||
<classifier>exec</classifier>
|
||||
<layers>
|
||||
<enabled>true</enabled>
|
||||
</layers>
|
||||
<image>
|
||||
<builder>paketobuildpacks/builder:tiny</builder>
|
||||
<env>
|
||||
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
|
||||
<BP_NATIVE_IMAGE>false</BP_NATIVE_IMAGE>
|
||||
<BPL_JFR_ENABLED>true</BPL_JFR_ENABLED>
|
||||
</env>
|
||||
</image>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.experimental</groupId>
|
||||
<artifactId>spring-aot-maven-plugin</artifactId>
|
||||
<version>${spring-native.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test-generate</id>
|
||||
<goals>
|
||||
<goal>test-generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>generate</id>
|
||||
<goals>
|
||||
<goal>generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${surefire-plugin.version}</version>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/*IT</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<id>spring-release</id>
|
||||
<name>Spring release</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<!-- This can be removed once a stable version of org.springframework.experimental:spring-aot-maven-plugin,
|
||||
compatible with latest JDK, is released. -->
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/libs-milestone-local</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<id>spring-release</id>
|
||||
<name>Spring release</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<!-- This can be removed once a stable version of org.springframework.experimental:spring-aot-maven-plugin,
|
||||
compatible with latest JDK, is released. -->
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/libs-milestone-local</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>native</id>
|
||||
<properties>
|
||||
<repackage.classifier>exec</repackage.classifier>
|
||||
<native-buildtools.version>0.9.3</native-buildtools.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.graalvm.buildtools</groupId>
|
||||
<artifactId>junit-platform-native</artifactId>
|
||||
<version>${native-buildtools.version}</version>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-launcher</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<layers>
|
||||
<enabled>true</enabled>
|
||||
</layers>
|
||||
<image>
|
||||
<builder>paketobuildpacks/builder:tiny</builder>
|
||||
<env>
|
||||
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
|
||||
<BPL_JFR_ENABLED>true</BPL_JFR_ENABLED>
|
||||
</env>
|
||||
</image>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.experimental</groupId>
|
||||
<artifactId>spring-aot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test-generate</id>
|
||||
<goals>
|
||||
<goal>test-generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>generate</id>
|
||||
<goals>
|
||||
<goal>generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>local-native</id>
|
||||
<properties>
|
||||
<repackage.classifier>exec</repackage.classifier>
|
||||
<native-buildtools.version>0.9.11</native-buildtools.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-launcher</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.experimental</groupId>
|
||||
<artifactId>spring-aot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test-generate</id>
|
||||
<goals>
|
||||
<goal>test-generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>generate</id>
|
||||
<goals>
|
||||
<goal>generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.graalvm.buildtools</groupId>
|
||||
<artifactId>native-maven-plugin</artifactId>
|
||||
<version>${native-buildtools.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<buildArgs combine.children="append">
|
||||
<buildArgs>-H:+AllowVMInspection</buildArgs>
|
||||
</buildArgs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test-native</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>build-native</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-native</id>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<phase>test</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M6</version>
|
||||
<configuration>
|
||||
<argLine>-DspringAot=true
|
||||
-agentlib:native-image-agent=access-filter-file=src/test/resources/access-filter.json,config-merge-dir=target/classes/META-INF/native-image</argLine>
|
||||
|
@ -185,9 +259,8 @@
|
|||
|
||||
<properties>
|
||||
<java.version>11</java.version>
|
||||
<repackage.classifier />
|
||||
<spring-native.version>0.11.0-RC1</spring-native.version>
|
||||
<log4j2.version>2.17.1</log4j2.version>
|
||||
<spring-native.version>0.12.1</spring-native.version>
|
||||
<surefire-plugin.version>3.0.0-M6</surefire-plugin.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
FROM openjdk:11
|
||||
|
||||
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
|
||||
|
||||
COPY --chown=1001 target/spring-project-0.1-SNAPSHOT-exec.jar /spring-app/
|
||||
|
||||
WORKDIR /spring-app
|
||||
|
||||
EXPOSE 8080
|
||||
USER 1001
|
||||
|
||||
ENTRYPOINT ["java", "-jar", "spring-project-0.1-SNAPSHOT-exec.jar" ]
|
|
@ -2,21 +2,25 @@ version: '3.1'
|
|||
|
||||
services:
|
||||
db:
|
||||
image: postgres
|
||||
image: mysql:5.7.38
|
||||
ports:
|
||||
- '5432:5432'
|
||||
- '3306:3306'
|
||||
environment:
|
||||
POSTGRES_PASSWORD: example
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: baeldung
|
||||
command: [ 'mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci' ]
|
||||
healthcheck:
|
||||
test: mysqladmin ping -h 127.0.0.1 -u $$MYSQL_USER --password=$$MYSQL_PASSWORD
|
||||
app:
|
||||
image: spring-project:0.1-SNAPSHOT
|
||||
ports:
|
||||
- '8080:8080'
|
||||
image: docker.io/library/spring-project:0.1-SNAPSHOT
|
||||
network_mode: "host"
|
||||
environment:
|
||||
DB_URL: r2dbc:postgresql://db:5432/postgres
|
||||
links:
|
||||
- "db"
|
||||
DB_URL: r2dbc:mysql://localhost:3306/baeldung?useSSL=true&requireSSL=true
|
||||
HOST_HOSTNAME: ${EXTERNAL_IP}
|
||||
depends_on:
|
||||
- "db"
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
db:
|
||||
condition: service_healthy
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '3.00'
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
package com.baeldung.spring_project;
|
||||
|
||||
import com.baeldung.spring_project.domain.ZIPRepo;
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
|
||||
import org.springframework.r2dbc.connection.R2dbcTransactionManager;
|
||||
import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer;
|
||||
import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator;
|
||||
import org.springframework.transaction.ReactiveTransactionManager;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableR2dbcRepositories
|
||||
public class Startup {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Startup.class, args).getBean(ZIPRepo.class).findById("");
|
||||
SpringApplication.run(Startup.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -34,4 +35,5 @@ public class Startup {
|
|||
@Bean ReactiveTransactionManager transactionManager(ConnectionFactory connectionFactory) {
|
||||
return new R2dbcTransactionManager(connectionFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,11 +2,14 @@ package com.baeldung.spring_project;
|
|||
|
||||
import com.baeldung.spring_project.domain.ZIPRepo;
|
||||
import com.baeldung.spring_project.domain.ZipCode;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.r2dbc.UncategorizedR2dbcException;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@RestController
|
||||
|
@ -21,7 +24,7 @@ public class ZipCodeApi {
|
|||
|
||||
@GetMapping("/{zipcode}")
|
||||
public Mono<ZipCode> findById(@PathVariable String zipcode) {
|
||||
return zipRepo.findById(zipcode);
|
||||
return getById(zipcode);
|
||||
}
|
||||
|
||||
@GetMapping("/by_city")
|
||||
|
@ -29,10 +32,23 @@ public class ZipCodeApi {
|
|||
return zipRepo.findByCity(city);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@PostMapping
|
||||
public Mono<ZipCode> create(@RequestBody ZipCode zipCode) {
|
||||
return zipRepo.findById(zipCode.getZip()).switchIfEmpty(Mono.defer(createZipCode(zipCode)));
|
||||
return getById(zipCode.getZip())
|
||||
.switchIfEmpty(Mono.defer(createZipCode(zipCode)))
|
||||
.onErrorResume(this::isKeyDuplicated, this.recoverWith(zipCode));
|
||||
}
|
||||
|
||||
private Mono<ZipCode> getById(String zipCode) {
|
||||
return zipRepo.findById(zipCode);
|
||||
}
|
||||
|
||||
private boolean isKeyDuplicated(Throwable ex) {
|
||||
return ex instanceof DataIntegrityViolationException || ex instanceof UncategorizedR2dbcException;
|
||||
}
|
||||
|
||||
private Function<? super Throwable, ? extends Mono<ZipCode>> recoverWith(ZipCode zipCode) {
|
||||
return throwable -> zipRepo.findById(zipCode.getZip());
|
||||
}
|
||||
|
||||
private Supplier<Mono<? extends ZipCode>> createZipCode(ZipCode zipCode) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
spring.r2dbc.url=${DB_URL:r2dbc:postgresql://localhost:5432/postgres}
|
||||
spring.r2dbc.username=postgres
|
||||
spring.r2dbc.password=example
|
||||
spring.r2dbc.pool.enabled=true
|
||||
spring.r2dbc.pool.maxSize=20
|
||||
spring.r2dbc.url=${DB_URL:r2dbc:mysql://localhost:3306/baeldung?useSSL=true&requireSSL=true}
|
||||
spring.r2dbc.properties.sslMode=required
|
||||
spring.r2dbc.username=root
|
||||
spring.r2dbc.password=root
|
||||
spring.r2dbc.pool.enabled=true
|
||||
spring.r2dbc.pool.maxSize=95
|
||||
|
||||
|
|
|
@ -1,9 +1,20 @@
|
|||
package com.baeldung.spring_project;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
@SpringBootTest
|
||||
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
|
||||
|
||||
@SpringBootTest(
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = { "spring.r2dbc.url=r2dbc:tc:mysql:///baeldung?TC_IMAGE_TAG=5.7.34"}
|
||||
)
|
||||
@TestInstance(value = PER_CLASS)
|
||||
@Testcontainers
|
||||
@Disabled
|
||||
class StartupIT {
|
||||
|
||||
@Test
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
Holtsville
|
||||
Adjuntas
|
||||
Aguada
|
||||
Aguadilla
|
||||
Maricao
|
||||
Anasco
|
||||
Angeles
|
||||
Arecibo
|
||||
Bajadero
|
||||
Barceloneta
|
||||
Boqueron
|
||||
Cabo Rojo
|
||||
Penuelas
|
||||
Camuy
|
||||
Castaner
|
||||
Rosario
|
||||
Sabana Grande
|
||||
Ciales
|
||||
Utuado
|
||||
Dorado
|
||||
Ensenada
|
||||
Florida
|
||||
Garrochales
|
||||
Guanica
|
||||
Guayanilla
|
||||
Hatillo
|
||||
Hormigueros
|
||||
Isabela
|
||||
Jayuya
|
||||
Lajas
|
||||
Lares
|
||||
Las Marias
|
||||
Manati
|
||||
Moca
|
||||
Rincon
|
||||
Quebradillas
|
||||
Mayaguez
|
||||
San German
|
||||
San Sebastian
|
||||
Morovis
|
||||
Sabana Hoyos
|
||||
San Antonio
|
||||
Vega Alta
|
||||
Vega Baja
|
||||
Yauco
|
||||
Aguas Buenas
|
||||
Aguirre
|
||||
Aibonito
|
||||
Maunabo
|
||||
Arroyo
|
||||
Mercedita
|
||||
Ponce
|
||||
Naguabo
|
||||
Naranjito
|
||||
Orocovis
|
||||
Palmer
|
||||
Patillas
|
||||
Caguas
|
||||
Canovanas
|
||||
Ceiba
|
||||
Cayey
|
||||
Fajardo
|
||||
Cidra
|
||||
Puerto Real
|
||||
Punta Santiago
|
||||
Roosevelt Roads
|
||||
Rio Blanco
|
||||
Rio Grande
|
||||
Salinas
|
||||
San Lorenzo
|
||||
Santa Isabel
|
||||
Vieques
|
||||
Villalba
|
||||
Yabucoa
|
||||
Coamo
|
||||
Las Piedras
|
||||
Loiza
|
||||
Luquillo
|
||||
Culebra
|
||||
Juncos
|
||||
Gurabo
|
||||
Coto Laurel
|
||||
Comerio
|
||||
Corozal
|
||||
Guayama
|
||||
La Plata
|
||||
Humacao
|
||||
Barranquitas
|
||||
Juana Diaz
|
||||
St Thomas
|
||||
Christiansted
|
||||
St John
|
||||
Frederiksted
|
||||
Kingshill
|
||||
San Juan
|
||||
Fort Buchanan
|
||||
Toa Baja
|
||||
Sabana Seca
|
||||
Toa Alta
|
||||
Bayamon
|
||||
Catano
|
||||
Guaynabo
|
||||
Trujillo Alto
|
||||
Saint Just
|
||||
Carolina
|
||||
Agawam
|
||||
Amherst
|
||||
Barre
|
||||
Belchertown
|
||||
Blandford
|
||||
Bondsville
|
||||
Brimfield
|
||||
Chester
|
||||
Chesterfield
|
||||
Chicopee
|
||||
Cummington
|
||||
Easthampton
|
||||
East Longmeadow
|
||||
East Otis
|
||||
Feeding Hills
|
||||
Gilbertville
|
||||
Goshen
|
||||
Granby
|
||||
Granville
|
||||
Hadley
|
||||
Hampden
|
||||
Hardwick
|
||||
Hatfield
|
||||
Haydenville
|
||||
Holyoke
|
||||
Huntington
|
||||
Leeds
|
||||
Leverett
|
||||
Ludlow
|
||||
Monson
|
||||
North Amherst
|
|
|
@ -0,0 +1,65 @@
|
|||
local require = require
|
||||
local json = require "json"
|
||||
|
||||
math.randomseed(os.time())
|
||||
|
||||
-- read csv lines
|
||||
function ParseCSVLine(line,sep)
|
||||
local res = {}
|
||||
local pos = 1
|
||||
sep = sep or ','
|
||||
while true do
|
||||
local c = string.sub(line,pos,pos)
|
||||
if (c == "") then break end
|
||||
if (c == '"') then
|
||||
local txt = ""
|
||||
repeat
|
||||
local startp,endp = string.find(line,'^%b""',pos)
|
||||
txt = txt..string.sub(line,startp+1,endp-1)
|
||||
pos = endp + 1
|
||||
c = string.sub(line,pos,pos)
|
||||
if (c == '"') then txt = txt..'"' end
|
||||
until (c ~= '"')
|
||||
table.insert(res,txt)
|
||||
assert(c == sep or c == "")
|
||||
pos = pos + 1
|
||||
else
|
||||
local startp,endp = string.find(line,sep,pos)
|
||||
if (startp) then
|
||||
table.insert(res,string.sub(line,pos,startp-1))
|
||||
pos = endp + 1
|
||||
else
|
||||
table.insert(res,string.sub(line,pos))
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
loadFile = function()
|
||||
local filename = "zip_code_database.csv"
|
||||
|
||||
local data = {}
|
||||
local count = 0
|
||||
local sep = ","
|
||||
|
||||
for line in io.lines(filename) do
|
||||
local values = ParseCSVLine(line,sep)
|
||||
data[count + 1] = { zip=values[1], type=values[2], city=values[4], state=values[7], county=values[8], timezone=values[9] }
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
generator = function()
|
||||
local data = loadFile()
|
||||
return coroutine.create(function()
|
||||
for k,v in pairs(data) do
|
||||
coroutine.yield(json.stringify(v))
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return generator()
|
|
@ -0,0 +1,79 @@
|
|||
local require = require
|
||||
local json = require "json"
|
||||
|
||||
math.randomseed(os.clock()*100000000000)
|
||||
|
||||
function ParseCSVLine(line,sep)
|
||||
local res = {}
|
||||
local pos = 1
|
||||
sep = sep or ','
|
||||
while true do
|
||||
local c = string.sub(line,pos,pos)
|
||||
if (c == "") then break end
|
||||
if (c == '"') then
|
||||
local txt = ""
|
||||
repeat
|
||||
local startp,endp = string.find(line,'^%b""',pos)
|
||||
txt = txt..string.sub(line,startp+1,endp-1)
|
||||
pos = endp + 1
|
||||
c = string.sub(line,pos,pos)
|
||||
if (c == '"') then txt = txt..'"' end
|
||||
until (c ~= '"')
|
||||
table.insert(res,txt)
|
||||
assert(c == sep or c == "")
|
||||
pos = pos + 1
|
||||
else
|
||||
local startp,endp = string.find(line,sep,pos)
|
||||
if (startp) then
|
||||
table.insert(res,string.sub(line,pos,startp-1))
|
||||
pos = endp + 1
|
||||
else
|
||||
table.insert(res,string.sub(line,pos))
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
loadFile = function()
|
||||
local filename = "cities.csv"
|
||||
|
||||
local data = {}
|
||||
local count = 0
|
||||
local sep = ","
|
||||
|
||||
for line in io.lines(filename) do
|
||||
local values = ParseCSVLine(line,sep)
|
||||
data[count + 1] = values[1]
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
local data = loadFile()
|
||||
|
||||
local urlencode = function (str)
|
||||
str = string.gsub (str, "([^0-9a-zA-Z !'()*._~-])", -- locale independent
|
||||
function (c) return string.format ("%%%02X", string.byte(c)) end)
|
||||
str = string.gsub (str, " ", "+")
|
||||
return str
|
||||
end
|
||||
|
||||
request = function()
|
||||
url_path = "/zipcode/by_city?city=" .. urlencode(data[math.random(1, 136)])
|
||||
|
||||
local headers = { ["Content-Type"] = "application/json;charset=UTF-8" }
|
||||
|
||||
return wrk.format("GET", url_path, headers, nil)
|
||||
end
|
||||
|
||||
done = function(summary, latency, requests)
|
||||
io.write("--------------GET CITY ZIPCODES----------------\n")
|
||||
for _, p in pairs({ 50, 90, 99, 99.999 }) do
|
||||
n = latency:percentile(p)
|
||||
io.write(string.format("%g%%,%d\n", p, n))
|
||||
end
|
||||
io.write("-----------------------------------------------\n\n")
|
||||
end
|
|
@ -0,0 +1,77 @@
|
|||
local require = require
|
||||
local json = require "json"
|
||||
|
||||
math.randomseed(os.clock()*100000000000)
|
||||
|
||||
function ParseCSVLine(line,sep)
|
||||
local res = {}
|
||||
local pos = 1
|
||||
sep = sep or ','
|
||||
while true do
|
||||
local c = string.sub(line,pos,pos)
|
||||
if (c == "") then break end
|
||||
if (c == '"') then
|
||||
local txt = ""
|
||||
repeat
|
||||
local startp,endp = string.find(line,'^%b""',pos)
|
||||
txt = txt..string.sub(line,startp+1,endp-1)
|
||||
pos = endp + 1
|
||||
c = string.sub(line,pos,pos)
|
||||
if (c == '"') then txt = txt..'"' end
|
||||
|
||||
until (c ~= '"')
|
||||
table.insert(res,txt)
|
||||
assert(c == sep or c == "")
|
||||
pos = pos + 1
|
||||
else
|
||||
local startp,endp = string.find(line,sep,pos)
|
||||
if (startp) then
|
||||
table.insert(res,string.sub(line,pos,startp-1))
|
||||
pos = endp + 1
|
||||
else
|
||||
table.insert(res,string.sub(line,pos))
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
loadFile = function()
|
||||
local filename = "zip_code_database.csv"
|
||||
|
||||
local data = {}
|
||||
local count = 0
|
||||
local sep = ","
|
||||
|
||||
for line in io.lines(filename) do
|
||||
local values = ParseCSVLine(line,sep)
|
||||
data[count + 1] = values[1]
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
local data = loadFile()
|
||||
|
||||
request = function()
|
||||
|
||||
local value = data[math.random(1, 12079)]
|
||||
|
||||
url_path = "/zipcode/" .. value
|
||||
|
||||
local headers = { ["Content-Type"] = "application/json;charset=UTF-8" }
|
||||
|
||||
return wrk.format("GET", url_path, headers, nil)
|
||||
end
|
||||
|
||||
|
||||
done = function(summary, latency, requests)
|
||||
io.write("--------------GET ZIPCODE----------------\n")
|
||||
for _, p in pairs({ 50, 90, 99, 99.999 }) do
|
||||
n = latency:percentile(p)
|
||||
io.write(string.format("%g%%,%d\n", p, n))
|
||||
end
|
||||
io.write("-----------------------------------------\n\n")
|
||||
end
|
|
@ -0,0 +1,133 @@
|
|||
local json = {}
|
||||
|
||||
local function kind_of(obj)
|
||||
if type(obj) ~= 'table' then return type(obj) end
|
||||
local i = 1
|
||||
for _ in pairs(obj) do
|
||||
if obj[i] ~= nil then i = i + 1 else return 'table' end
|
||||
end
|
||||
if i == 1 then return 'table' else return 'array' end
|
||||
end
|
||||
|
||||
local function escape_str(s)
|
||||
local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'}
|
||||
local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'}
|
||||
for i, c in ipairs(in_char) do
|
||||
s = s:gsub(c, '\\' .. out_char[i])
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
local function skip_delim(str, pos, delim, err_if_missing)
|
||||
pos = pos + #str:match('^%s*', pos)
|
||||
if str:sub(pos, pos) ~= delim then
|
||||
if err_if_missing then
|
||||
error('Expected ' .. delim .. ' near position ' .. pos)
|
||||
end
|
||||
return pos, false
|
||||
end
|
||||
return pos + 1, true
|
||||
end
|
||||
|
||||
local function parse_str_val(str, pos, val)
|
||||
val = val or ''
|
||||
local early_end_error = 'End of input found while parsing string.'
|
||||
if pos > #str then error(early_end_error) end
|
||||
local c = str:sub(pos, pos)
|
||||
if c == '"' then return val, pos + 1 end
|
||||
if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end
|
||||
local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'}
|
||||
local nextc = str:sub(pos + 1, pos + 1)
|
||||
if not nextc then error(early_end_error) end
|
||||
return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc))
|
||||
end
|
||||
|
||||
local function parse_num_val(str, pos)
|
||||
local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos)
|
||||
local val = tonumber(num_str)
|
||||
if not val then error('Error parsing number at position ' .. pos .. '.') end
|
||||
return val, pos + #num_str
|
||||
end
|
||||
|
||||
function json.stringify(obj, as_key)
|
||||
local s = {}
|
||||
local kind = kind_of(obj)
|
||||
if kind == 'array' then
|
||||
if as_key then error('Can\'t encode array as key.') end
|
||||
s[#s + 1] = '['
|
||||
for i, val in ipairs(obj) do
|
||||
if i > 1 then s[#s + 1] = ', ' end
|
||||
s[#s + 1] = json.stringify(val)
|
||||
end
|
||||
s[#s + 1] = ']'
|
||||
elseif kind == 'table' then
|
||||
if as_key then error('Can\'t encode table as key.') end
|
||||
s[#s + 1] = '{'
|
||||
for k, v in pairs(obj) do
|
||||
if #s > 1 then s[#s + 1] = ', ' end
|
||||
s[#s + 1] = json.stringify(k, true)
|
||||
s[#s + 1] = ':'
|
||||
s[#s + 1] = json.stringify(v)
|
||||
end
|
||||
s[#s + 1] = '}'
|
||||
elseif kind == 'string' then
|
||||
return '"' .. escape_str(obj) .. '"'
|
||||
elseif kind == 'number' then
|
||||
if as_key then return '"' .. tostring(obj) .. '"' end
|
||||
return tostring(obj)
|
||||
elseif kind == 'boolean' then
|
||||
return tostring(obj)
|
||||
elseif kind == 'nil' then
|
||||
return 'null'
|
||||
else
|
||||
error('Unjsonifiable type: ' .. kind .. '.')
|
||||
end
|
||||
return table.concat(s)
|
||||
end
|
||||
|
||||
json.null = {}
|
||||
|
||||
function json.parse(str, pos, end_delim)
|
||||
pos = pos or 1
|
||||
if pos > #str then error('Reached unexpected end of input.') end
|
||||
local pos = pos + #str:match('^%s*', pos)
|
||||
local first = str:sub(pos, pos)
|
||||
if first == '{' then
|
||||
local obj, key, delim_found = {}, true, true
|
||||
pos = pos + 1
|
||||
while true do
|
||||
key, pos = json.parse(str, pos, '}')
|
||||
if key == nil then return obj, pos end
|
||||
if not delim_found then error('Comma missing between object items.') end
|
||||
pos = skip_delim(str, pos, ':', true)
|
||||
obj[key], pos = json.parse(str, pos)
|
||||
pos, delim_found = skip_delim(str, pos, ',')
|
||||
end
|
||||
elseif first == '[' then
|
||||
local arr, val, delim_found = {}, true, true
|
||||
pos = pos + 1
|
||||
while true do
|
||||
val, pos = json.parse(str, pos, ']')
|
||||
if val == nil then return arr, pos end
|
||||
if not delim_found then error('Comma missing between array items.') end
|
||||
arr[#arr + 1] = val
|
||||
pos, delim_found = skip_delim(str, pos, ',')
|
||||
end
|
||||
elseif first == '"' then
|
||||
return parse_str_val(str, pos + 1)
|
||||
elseif first == '-' or first:match('%d') then
|
||||
return parse_num_val(str, pos)
|
||||
elseif first == end_delim then
|
||||
return nil, pos + 1
|
||||
else
|
||||
local literals = {['true'] = true, ['false'] = false, ['null'] = json.null}
|
||||
for lit_str, lit_val in pairs(literals) do
|
||||
local lit_end = pos + #lit_str - 1
|
||||
if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end
|
||||
end
|
||||
local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10)
|
||||
error('Invalid json syntax starting at ' .. pos_info_str)
|
||||
end
|
||||
end
|
||||
|
||||
return json
|
|
@ -0,0 +1,73 @@
|
|||
local require = require
|
||||
local json = require "json"
|
||||
|
||||
math.randomseed(os.clock()*100000000000)
|
||||
|
||||
function ParseCSVLine(line,sep)
|
||||
local res = {}
|
||||
local pos = 1
|
||||
sep = sep or ','
|
||||
while true do
|
||||
local c = string.sub(line,pos,pos)
|
||||
if (c == "") then break end
|
||||
if (c == '"') then
|
||||
local txt = ""
|
||||
repeat
|
||||
local startp,endp = string.find(line,'^%b""',pos)
|
||||
txt = txt..string.sub(line,startp+1,endp-1)
|
||||
pos = endp + 1
|
||||
c = string.sub(line,pos,pos)
|
||||
if (c == '"') then txt = txt..'"' end
|
||||
|
||||
until (c ~= '"')
|
||||
table.insert(res,txt)
|
||||
assert(c == sep or c == "")
|
||||
pos = pos + 1
|
||||
else
|
||||
local startp,endp = string.find(line,sep,pos)
|
||||
if (startp) then
|
||||
table.insert(res,string.sub(line,pos,startp-1))
|
||||
pos = endp + 1
|
||||
else
|
||||
table.insert(res,string.sub(line,pos))
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
loadFile = function()
|
||||
local filename = "zip_code_database.csv"
|
||||
|
||||
local data = {}
|
||||
local count = 0
|
||||
local sep = ","
|
||||
|
||||
for line in io.lines(filename) do
|
||||
local values = ParseCSVLine(line,sep)
|
||||
data[count + 1] = { zip=values[1], type=values[2], city=values[4], state=values[7], county=values[8], timezone=values[9] }
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
local data = loadFile()
|
||||
|
||||
request = function()
|
||||
local url_path = "/zipcode"
|
||||
local val = data[math.random(1, 12079)]
|
||||
|
||||
local headers = { ["Content-Type"] = "application/json;charset=UTF-8" }
|
||||
return wrk.format("POST", url_path, headers, json.stringify(val))
|
||||
end
|
||||
|
||||
done = function(summary, latency, requests)
|
||||
io.write("--------------POST ZIPCODE----------------\n")
|
||||
for _, p in pairs({ 50, 75, 90, 99, 99.999 }) do
|
||||
n = latency:percentile(p)
|
||||
io.write(string.format("%g%%,%d\n", p, n))
|
||||
end
|
||||
io.write("------------------------------------------\n\n")
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
$wrk_home/wrk -t1 -c5 -d1m -s ./post_zipcode.lua --timeout 2m -H 'Host: localhost' http://localhost:8080 & sleep 60
|
||||
|
||||
$wrk_home/wrk -t1 -c20 -d5m -s ./post_zipcode.lua --timeout 2m -H 'Host: localhost' http://localhost:8080 & sleep 60
|
||||
|
||||
$wrk_home/wrk -t1 -c20 -d5m -s ./get_by_city.lua --timeout 2m -H 'Host: localhost' http://localhost:8080 \ &
|
||||
$wrk_home/wrk -t1 -c20 -d5m -s ./get_zipcode.lua --timeout 2m -H 'Host: localhost' http://localhost:8080 \ & sleep 120
|
||||
|
||||
$wrk_home/wrk -t2 -c10 -d3m -s ./get_by_city.lua --timeout 2m -H 'Host: localhost' http://localhost:8080 \ &
|
||||
$wrk_home/wrk -t2 -c10 -d3m -s ./get_zipcode.lua --timeout 2m -H 'Host: localhost' http://localhost:8080 \ &
|
||||
|
||||
wait
|
||||
|
Loading…
Reference in New Issue