From 5c6d54c4595aa6d76d39cee8534790651ff3d6ac Mon Sep 17 00:00:00 2001 From: Florian THIERRY Date: Thu, 9 Oct 2025 17:49:42 +0200 Subject: [PATCH] Add documentation. --- README.md | 77 ++++++++++++++++++ doc/images/models.png | Bin 0 -> 35432 bytes ...urces_of_model_schema_built_with_umlet.uxf | 37 +++++++++ k6-load-tests/configuration.yml | 3 - k6-load-tests/package.json | 5 +- k6-load-tests/src/apis/marketplace-apis.ts | 5 +- k6-load-tests/src/tests/config.ts | 7 +- local/postgresql/.gitkeep | 0 8 files changed, 123 insertions(+), 11 deletions(-) create mode 100644 README.md create mode 100644 doc/images/models.png create mode 100644 doc/sources_of_model_schema_built_with_umlet.uxf delete mode 100644 k6-load-tests/configuration.yml create mode 100644 local/postgresql/.gitkeep diff --git a/README.md b/README.md new file mode 100644 index 0000000..ffe7b61 --- /dev/null +++ b/README.md @@ -0,0 +1,77 @@ +# Virtual threads experiences +## General information +This project aims to show what is the developer experience when the virtual threads are used, in comparison of the framework Reactor. + +Therefore, there is one spring boot application which uses "standard java code" with virtual threads, and another spring boot application which uses Reactor. + +## Spring boot applications +### Common concepts +Both applications are developed to serve same endpoints with same models. + + + +### Architecture +Both applications are architectured with a "light" version of the hexagonal architecture. + +Java packages represent the hexagonal architecture modules: +- domain (Business code) +- exposition (Rest API) +- infrastructure (JPA layer) + +#### Models +[](./doc/images/models.png) + +#### Exposed endpoints + - Catalogs + - GET /api/catalogs/{catalogId} + - Items + - GET /api/items + - POST /api/items + - Marketplace + - GET /api/marketplace + +### Virtual threads application +The application runs on port `51001`. + +```bash +./gradlew :virtual-threads-app:bootRun +``` + +### Reactor application +The application runs on port `52001`. + +To start the application, run this command: +```bash +./gradlew :reactor-app:bootRun +``` + +## Database +The database is a PostgreSQL database which runs inside a container. + +To start the database, just run this command inside the project root folder: +```bash +docker compose up --detach --file ./docker-compose.yml +``` + +Then, you will have to initialise the tables by executing scripts located [there](./src/main/sql/init_database.sql) into the container. + +You can connect to it with this "unix" command: +```bash +docker exec --interactive --tty virtual-threads-test-db /bin/bash +psql --host localhost --port 5432 --username virtual_threads_test_user virtual_threads_test_db +``` + +### Database files +There is a volumes for the database container, which points to this location: [local/postgresql](./local/postgresql). + +## Bruno http client collection +There is a collection of queries, usable with [bruno](https://www.usebruno.com/). It is located inside the [rest-client-collection](./rest-client-collection). + +## Load testing +Load tests use K6 framework. + +### Targeting the application to test +By default, tests are configured to load the `virtual-threads-app`. + +If you want to run them on the `reactor-app`, you have to edit the variable `TARGET_URL` inside the file [config.ts](./k6-load-tests/src/tests/config.ts). + diff --git a/doc/images/models.png b/doc/images/models.png new file mode 100644 index 0000000000000000000000000000000000000000..55102c5f18f6a97a3052cfa944db520d9018b9de GIT binary patch literal 35432 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 Xk%JnewJKhS$1`Wf!s+2tSN;4Sa((7N literal 0 HcmV?d00001 diff --git a/doc/sources_of_model_schema_built_with_umlet.uxf b/doc/sources_of_model_schema_built_with_umlet.uxf new file mode 100644 index 0000000..49a36a9 --- /dev/null +++ b/doc/sources_of_model_schema_built_with_umlet.uxf @@ -0,0 +1,37 @@ +10UMLClass7305009060Catalog +-- +id: UUID +name: StringUMLClass73058018080Item +-- +id: UUID +name: String +sharedDate: ZonedDateTimeUMLClass5904109050Marketplace +-- +Relation620450130100lt=- +m1=0..* +m2=0..*10;10;10;70;110;70Relation590450160180lt=- +m1=0..* +m2=0..*10;10;10;150;140;150UMLNote55034040030Domain +bg=blueUMLNote2034040030Exposition +bg=redUMLNote108034040030Infrastructure +bg=greenRelation90450130100lt=- +m1=0..* +m2=0..*10;10;10;70;110;70Relation60450160180lt=- +m1=0..* +m2=0..*10;10;10;150;140;150UMLClass2005009060CatalogDto +-- +id: UUID +name: StringUMLClass20058018080ItemDto +-- +id: UUID +name: String +isShared: BooleanUMLClass5041011050MarketplaceDto +-- +UMLClass112047013060CatalogJpaEntity +-- +id: UUID +name: StringUMLClass128046018080ItemJpaEntity +-- +id: UUID +name: String +sharedDate: ZonedDateTime \ No newline at end of file diff --git a/k6-load-tests/configuration.yml b/k6-load-tests/configuration.yml deleted file mode 100644 index 9118bdb..0000000 --- a/k6-load-tests/configuration.yml +++ /dev/null @@ -1,3 +0,0 @@ -target: - url: http://localhost - port: 51001 \ No newline at end of file diff --git a/k6-load-tests/package.json b/k6-load-tests/package.json index 522ddca..a1b9e6f 100644 --- a/k6-load-tests/package.json +++ b/k6-load-tests/package.json @@ -6,10 +6,7 @@ "type": "module", "scripts": { "build": "vite build", - "test:demo": "yarn build && k6 run dist/tests/load-tests.cjs", - "test:demo-stages": "yarn build && k6 run dist/tests/reqres-stages.cjs", - "test-with-monitoring:demo": "yarn build && docker run --platform linux/amd64 -it -p 5665:5665 -v $(pwd)/dist/:/src ghcr.io/grafana/xk6-dashboard:0.6.1 run --out 'dashboard=period=2s' /src/tests/reqres.cjs", - "test-with-monitoring:demo-stages": "yarn build && docker run --platform linux/amd64 -it -p 5665:5665 -v $(pwd)/dist/:/src ghcr.io/grafana/xk6-dashboard:0.6.1 run --out 'dashboard=period=2s' /src/tests/reqres-stages.cjs" + "start": "yarn build && k6 run dist/tests/load-tests.cjs" }, "devDependencies": { "@babel/core": "7.23.3", diff --git a/k6-load-tests/src/apis/marketplace-apis.ts b/k6-load-tests/src/apis/marketplace-apis.ts index 3ae3bbe..d455e09 100644 --- a/k6-load-tests/src/apis/marketplace-apis.ts +++ b/k6-load-tests/src/apis/marketplace-apis.ts @@ -4,6 +4,7 @@ import {logWaitingTime} from "../utils/logger"; import {Trend} from "k6/metrics"; import {check} from "k6"; import {Response} from "../data/common"; +import {TARGET_URL} from "../tests/config"; // Metrics that we want to track const metrics = { @@ -11,9 +12,7 @@ const metrics = { }; export const getMarketplace = (): Response => { - const serverUrl = `http://localhost:51001`; - - const urlToTest = `${serverUrl}/api/marketplace`; + const urlToTest = `${TARGET_URL}/api/marketplace`; const response = http.get(urlToTest); logWaitingTime({ diff --git a/k6-load-tests/src/tests/config.ts b/k6-load-tests/src/tests/config.ts index 267dcdc..8088f40 100644 --- a/k6-load-tests/src/tests/config.ts +++ b/k6-load-tests/src/tests/config.ts @@ -1 +1,6 @@ -export const VUs = 1 \ No newline at end of file +export const VUs = 1; +// @ts-ignore - if it is unused +const VIRTUAL_THREADS_APP_PORT = 51001; +// @ts-ignore - if it is unused +const REACTOR_APP_PORT = 52001; +export const TARGET_URL = `http://localhost:${VIRTUAL_THREADS_APP_PORT}`; \ No newline at end of file diff --git a/local/postgresql/.gitkeep b/local/postgresql/.gitkeep new file mode 100644 index 0000000..e69de29