diff --git a/.github/workflows/slo.yaml b/.github/workflows/slo.yaml
new file mode 100644
index 0000000..c46207a
--- /dev/null
+++ b/.github/workflows/slo.yaml
@@ -0,0 +1,67 @@
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+ workflow_dispatch:
+
+name: SLO
+
+jobs:
+ test-slo:
+ concurrency:
+ group: slo-${{ github.ref }}
+ if: (!contains(github.event.pull_request.labels.*.name, 'no slo'))
+
+ runs-on: ubuntu-latest
+ name: SLO test
+ permissions:
+ checks: write
+ pull-requests: write
+ contents: read
+ issues: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ if: env.DOCKER_REPO != null
+ env:
+ DOCKER_REPO: ${{ secrets.SLO_DOCKER_REPO }}
+
+ - name: Run SLO
+ uses: ydb-platform/slo-tests@main
+ if: env.DOCKER_REPO != null
+ env:
+ DOCKER_REPO: ${{ secrets.SLO_DOCKER_REPO }}
+ continue-on-error: true
+ with:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ KUBECONFIG_B64: ${{ secrets.SLO_KUBE_CONFIG }}
+ AWS_CREDENTIALS_B64: ${{ secrets.SLO_AWS_CREDENTIALS }}
+ AWS_CONFIG_B64: ${{ secrets.SLO_AWS_CONFIG }}
+ DOCKER_USERNAME: ${{ secrets.SLO_DOCKER_USERNAME }}
+ DOCKER_PASSWORD: ${{ secrets.SLO_DOCKER_PASSWORD }}
+ DOCKER_REPO: ${{ secrets.SLO_DOCKER_REPO }}
+ DOCKER_FOLDER: ${{ secrets.SLO_DOCKER_FOLDER }}
+ s3_endpoint: ${{ secrets.SLO_S3_ENDPOINT }}
+ s3_images_folder: ${{ vars.SLO_S3_IMAGES_FOLDER }}
+ grafana_domain: ${{ vars.SLO_GRAFANA_DOMAIN }}
+ grafana_dashboard: ${{ vars.SLO_GRAFANA_DASHBOARD }}
+ grafana_dashboard_width: 2000
+ grafana_dashboard_height: 2300
+ ydb_version: 'newest'
+ timeBetweenPhases: 30
+ shutdownTime: 30
+
+ language_id0: 'hibernate'
+ workload_path0: 'slo'
+ language0: 'Hibernate YQL Dialect over YDB JDBC Driver'
+ workload_build_options0: -f Dockerfile --build-arg SRC_PATH=hibernate
+
+ - uses: actions/upload-artifact@v3
+ if: always() && env.DOCKER_REPO != null
+ env:
+ DOCKER_REPO: ${{ secrets.SLO_DOCKER_REPO }}
+ with:
+ name: slo-logs
+ path: logs/
diff --git a/liquibase-dialect/pom.xml b/liquibase-dialect/pom.xml
index a5b0826..e195760 100644
--- a/liquibase-dialect/pom.xml
+++ b/liquibase-dialect/pom.xml
@@ -43,7 +43,7 @@
1.8
4.24.0
- 2.2.0
+ 2.2.8
diff --git a/slo/Dockerfile b/slo/Dockerfile
new file mode 100644
index 0000000..d08891d
--- /dev/null
+++ b/slo/Dockerfile
@@ -0,0 +1,13 @@
+FROM maven:3.8.4-openjdk-17 AS build
+ARG SRC_PATH
+COPY . /app
+RUN ls
+WORKDIR /app/${SRC_PATH}
+RUN ls
+RUN mvn package -DskipTests
+RUN cp -r ./target/* ./..
+RUN ls ..
+
+FROM openjdk:21 AS run
+COPY --from=build /app .
+ENTRYPOINT ["java", "-jar", "./slo.jar"]
\ No newline at end of file
diff --git a/slo/config/grafana/provisioning/dashboards/dashboard.yml b/slo/config/grafana/provisioning/dashboards/dashboard.yml
new file mode 100644
index 0000000..c678414
--- /dev/null
+++ b/slo/config/grafana/provisioning/dashboards/dashboard.yml
@@ -0,0 +1,6 @@
+apiVersion: 1
+
+providers:
+ - name: 'SLO'
+ options:
+ path: /etc/grafana/provisioning/dashboards
diff --git a/slo/config/grafana/provisioning/dashboards/slo.json b/slo/config/grafana/provisioning/dashboards/slo.json
new file mode 100644
index 0000000..69d76bf
--- /dev/null
+++ b/slo/config/grafana/provisioning/dashboards/slo.json
@@ -0,0 +1,646 @@
+{
+ "annotations": {
+ "list": [
+ {
+ "builtIn": 1,
+ "datasource": {
+ "type": "grafana",
+ "uid": "-- Grafana --"
+ },
+ "enable": true,
+ "hide": true,
+ "iconColor": "rgba(0, 211, 255, 1)",
+ "name": "Annotations & Alerts",
+ "target": {
+ "limit": 100,
+ "matchAny": false,
+ "tags": [],
+ "type": "dashboard"
+ },
+ "type": "dashboard"
+ }
+ ]
+ },
+ "editable": true,
+ "fiscalYearStartMonth": 0,
+ "graphTooltip": 0,
+ "links": [],
+ "liveNow": false,
+ "panels": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 0,
+ "y": 0
+ },
+ "id": 12,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "editorMode": "builder",
+ "expr": "rate(oks[$__rate_interval]) > 0",
+ "hide": false,
+ "legendFormat": "({{sdk}}-{{sdkVersion}}) {{jobName}} OK",
+ "range": true,
+ "refId": "B"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "editorMode": "builder",
+ "expr": "rate(not_oks[$__rate_interval]) > 0",
+ "hide": false,
+ "legendFormat": "({{sdk}}-{{sdkVersion}}) {{jobName}} not OK",
+ "range": true,
+ "refId": "C"
+ }
+ ],
+ "title": "SLO Requests RPS",
+ "transformations": [],
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "axisSoftMin": 0,
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "decimals": 0,
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 9,
+ "w": 12,
+ "x": 12,
+ "y": 0
+ },
+ "id": 14,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "editorMode": "builder",
+ "expr": "histogram_quantile(1, rate(attempts_bucket[$__rate_interval]))",
+ "hide": false,
+ "legendFormat": "{{sdk}}-{{sdkVersion}} {{jobName}}-{{status}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Attempts",
+ "transformations": [],
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 9
+ },
+ "id": 7,
+ "panels": [],
+ "title": "Latencies",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 0,
+ "y": 10
+ },
+ "id": 4,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "pluginVersion": "9.3.1",
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "editorMode": "builder",
+ "expr": "latency{jobName=\"read\", status=\"ok\"} > 0",
+ "legendFormat": "{{sdk}}-{{sdkVersion}}-p{{quantile}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Read Latencies (OK)",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 12,
+ "y": 10
+ },
+ "id": 5,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "editorMode": "builder",
+ "expr": "latency{jobName=\"write\", status=\"ok\"} > 0",
+ "legendFormat": "{{sdk}}-{{sdkVersion}}-p{{quantile}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Write Latencies (OK)",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 0,
+ "y": 18
+ },
+ "id": 10,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "editorMode": "builder",
+ "expr": "latency{jobName=\"read\", status=\"err\"} > 0",
+ "legendFormat": "{{sdk}}-{{sdkVersion}}-p{{quantile}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Read Latencies (NOT OK)",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 12,
+ "y": 18
+ },
+ "id": 11,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "editorMode": "builder",
+ "expr": "latency{jobName=\"write\", status=\"err\"} > 0",
+ "legendFormat": "{{sdk}}-{{sdkVersion}}-p{{quantile}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Write Latencies (NOT OK)",
+ "type": "timeseries"
+ }
+ ],
+ "refresh": "",
+ "revision": 1,
+ "schemaVersion": 38,
+ "style": "dark",
+ "tags": [],
+ "templating": {
+ "list": [
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "filters": [],
+ "hide": 0,
+ "label": "",
+ "name": "filter",
+ "skipUrlSync": false,
+ "type": "adhoc"
+ }
+ ]
+ },
+ "time": {
+ "from": "now-15m",
+ "to": "now"
+ },
+ "timepicker": {},
+ "timezone": "",
+ "title": "SLO",
+ "uid": "7CzMl5t4k",
+ "version": 1,
+ "weekStart": ""
+}
diff --git a/slo/config/grafana/provisioning/datasources/datasource.yml b/slo/config/grafana/provisioning/datasources/datasource.yml
new file mode 100644
index 0000000..0b62b9c
--- /dev/null
+++ b/slo/config/grafana/provisioning/datasources/datasource.yml
@@ -0,0 +1,11 @@
+apiVersion: 1
+
+datasources:
+ - name: prometheus
+ type: prometheus
+ access: proxy
+ orgId: 1
+ url: http://prometheus:9090
+ basicAuth: false
+ isDefault: true
+ editable: true
diff --git a/slo/config/prometheus/prometheus.yml b/slo/config/prometheus/prometheus.yml
new file mode 100644
index 0000000..281b390
--- /dev/null
+++ b/slo/config/prometheus/prometheus.yml
@@ -0,0 +1,8 @@
+global:
+ scrape_interval: 1s
+ evaluation_interval: 1s
+
+scrape_configs:
+ - job_name: 'slo'
+ static_configs:
+ - targets: ['prometheus-pushgateway:9091']
diff --git a/slo/docker-compose.yml b/slo/docker-compose.yml
new file mode 100644
index 0000000..a2843a3
--- /dev/null
+++ b/slo/docker-compose.yml
@@ -0,0 +1,107 @@
+version: '2.1'
+
+networks:
+ monitor-net:
+ driver: bridge
+
+services:
+ prometheus:
+ image: prom/prometheus:v2.44.0
+ container_name: prometheus
+ user: "$UID:$GID"
+ volumes:
+ - ./configs/prometheus:/etc/prometheus
+ - ../data/prometheus:/prometheus
+ command:
+ - '--config.file=/etc/prometheus/prometheus.yml'
+ - '--storage.tsdb.path=/prometheus'
+ - '--storage.tsdb.retention.time=200h'
+ - '--web.enable-lifecycle'
+ restart: unless-stopped
+ ports:
+ - "9090:9090"
+ networks:
+ - monitor-net
+
+ prometheus-pushgateway:
+ image: prom/pushgateway:v1.6.0
+ container_name: prometheus-pushgateway
+ ports:
+ - "9091:9091"
+ networks:
+ - monitor-net
+
+ grafana:
+ image: grafana/grafana:9.5.3
+ container_name: grafana
+ user: "$UID:$GID"
+ volumes:
+ - ./configs/grafana/provisioning:/etc/grafana/provisioning
+ - ../data/grafana:/var/lib/grafana
+ environment:
+ - GF_SECURITY_ADMIN_USER=admin
+ - GF_SECURITY_ADMIN_PASSWORD=password
+ restart: unless-stopped
+ ports:
+ - "3000:3000"
+ networks:
+ - monitor-net
+ ydb:
+ image: cr.yandex/yc/yandex-docker-local-ydb:latest
+ container_name: ydb
+ environment:
+ - GRPC_TLS_PORT=2135
+ - GRPC_PORT=2136
+ - MON_PORT=8765
+ - YDB_USE_IN_MEMORY_PDISKS=true
+ - YDB_DEFAULT_LOG_LEVEL=NOTICE
+ ports:
+ - "2135:2135"
+ - "2136:2136"
+ - "8765:8765"
+ volumes:
+ - ../data/ydb_certs:/ydb_certs
+ networks:
+ - monitor-net
+
+ slo-create:
+ build:
+ dockerfile: ./Dockerfile
+ args:
+ - SRC_PATH=hibernate
+ command:
+ - 'create'
+ - 'http://ydb:2136'
+ - '/local'
+ - '--table-name'
+ - 'slo-dotnet'
+ - '--min-partitions-count'
+ - '6'
+ - '--max-partitions-count'
+ - '1000'
+ - '--partition-size'
+ - '1'
+ - '--initial-data-count'
+ - '1000'
+ networks:
+ - monitor-net
+ depends_on:
+ ydb:
+ condition: service_healthy
+
+ slo-run:
+ build:
+ dockerfile: ./Dockerfile
+ command:
+ - 'run'
+ - 'http://ydb:2136'
+ - '/local'
+ - '--prom-pgw'
+ - 'http://prometheus-pushgateway:9091'
+ - '--table-name'
+ - 'slo-dotnet'
+ networks:
+ - monitor-net
+ depends_on:
+ slo-create:
+ condition: service_completed_successfully
\ No newline at end of file
diff --git a/slo/hibernate/pom.xml b/slo/hibernate/pom.xml
new file mode 100644
index 0000000..9ab25cb
--- /dev/null
+++ b/slo/hibernate/pom.xml
@@ -0,0 +1,64 @@
+
+
+ 4.0.0
+
+ ydb.tech
+ slo
+ 0.0.1-SNAPSHOT
+
+ hibernate
+ 0.0.1-SNAPSHOT
+ hibernate
+ hibernate
+
+ 21
+ 1.9.25
+ 0.9.5
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.springframework.retry
+ spring-retry
+
+
+ tech.ydb.dialects
+ hibernate-ydb-dialect
+ ${hibernate.ydb.dialect.version}
+
+
+
+
+ slo
+ ${project.basedir}/src/main/kotlin
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+
+
+ -Xjsr305=strict
+
+
+ spring
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-allopen
+ ${kotlin.version}
+
+
+
+
+
+
diff --git a/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/HibernateApplication.kt b/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/HibernateApplication.kt
new file mode 100644
index 0000000..3544642
--- /dev/null
+++ b/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/HibernateApplication.kt
@@ -0,0 +1,73 @@
+package tech.ydb.slo.hibernate
+
+import io.prometheus.metrics.core.metrics.Counter
+import io.prometheus.metrics.exporter.pushgateway.PushGateway
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.CommandLineRunner
+import org.springframework.boot.autoconfigure.SpringBootApplication
+import org.springframework.boot.runApplication
+import tech.ydb.slo.hibernate.service.SloService
+import java.time.Duration
+import java.time.Instant
+import java.util.concurrent.Executors
+
+
+@SpringBootApplication
+class HibernateApplication : CommandLineRunner {
+
+ @Autowired
+ private lateinit var sloService: SloService
+
+ override fun run(vararg args: String) {
+ if (args[0] == "create") {
+ return
+ }
+
+ val pushGateway = PushGateway.builder()
+ .job("workload-hibernate")
+ .address("prometheus-pushgateway:9091")
+ .build()
+
+ val okCount = Counter.builder().name("oks")
+ .labelNames("jobName", "sdk", "sdkVersion")
+ .help("Count of OK")
+ .register()
+ val notOkCount = Counter.builder().name("not_oks")
+ .labelNames("jobName", "sdk", "sdkVersion")
+ .help("Count of not OK")
+ .register()
+
+ val workersRead = Executors.newFixedThreadPool(3)
+ val workersWrite = Executors.newFixedThreadPool(1)
+
+ val startTime = Instant.now()
+
+ while (Instant.now() < startTime.plus(Duration.ofSeconds(10))) {
+ workersRead.submit {
+ try {
+ sloService.find()
+ okCount.labelValues("read", "TODO", "hibernate").inc()
+ } catch (e: Exception) {
+ notOkCount.labelValues("read", "TODO", "hibernate").inc()
+ }
+ pushGateway.push()
+ }
+
+ workersWrite.submit {
+ try {
+ sloService.save()
+ okCount.labelValues("write", "TODO", "hibernate").inc()
+ } catch (e: Exception) {
+ notOkCount.labelValues("write", "TODO", "hibernate").inc()
+ }
+ pushGateway.push()
+ }
+ }
+
+ pushGateway.delete()
+ }
+}
+
+fun main(args: Array) {
+ runApplication(*args)
+}
diff --git a/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/entity/SloEntity.kt b/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/entity/SloEntity.kt
new file mode 100644
index 0000000..43a4ab6
--- /dev/null
+++ b/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/entity/SloEntity.kt
@@ -0,0 +1,31 @@
+package tech.ydb.slo.hibernate.entity
+
+import jakarta.annotation.Nonnull
+import jakarta.persistence.Column
+import jakarta.persistence.Entity
+import jakarta.persistence.Id
+import jakarta.persistence.Table
+import java.time.Instant
+
+/**
+ * @author Kirill Kurdyukov
+ */
+@Entity
+@Table(name = "slo-hibernate")
+class SloEntity {
+
+ @Id
+ var id: Int = 0
+
+ @Nonnull
+ @Column(name = "payload_str")
+ lateinit var payloadStr: String
+
+ @Nonnull
+ @Column(name = "payload_double")
+ var payloadDouble: Double = 0.0
+
+ @Nonnull
+ @Column(name = "payload_timestamp")
+ lateinit var payloadTimestamp: Instant
+}
\ No newline at end of file
diff --git a/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/repository/SloEntityRepository.kt b/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/repository/SloEntityRepository.kt
new file mode 100644
index 0000000..adf3a2b
--- /dev/null
+++ b/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/repository/SloEntityRepository.kt
@@ -0,0 +1,10 @@
+package tech.ydb.slo.hibernate.repository
+
+import org.springframework.data.repository.CrudRepository
+import tech.ydb.slo.hibernate.entity.SloEntity
+
+
+/**
+ * @author Kirill Kurdyukov
+ */
+interface SloEntityRepository : CrudRepository
\ No newline at end of file
diff --git a/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/retry/YdbRetryable.kt b/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/retry/YdbRetryable.kt
new file mode 100644
index 0000000..ff31cad
--- /dev/null
+++ b/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/retry/YdbRetryable.kt
@@ -0,0 +1,19 @@
+package tech.ydb.slo.hibernate.retry
+
+import org.springframework.retry.annotation.Backoff
+import org.springframework.retry.annotation.Retryable
+import java.sql.SQLRecoverableException
+
+@Target(
+ AnnotationTarget.FUNCTION,
+ AnnotationTarget.PROPERTY_GETTER,
+ AnnotationTarget.PROPERTY_SETTER,
+ AnnotationTarget.CLASS
+)
+@Retention(AnnotationRetention.RUNTIME)
+@Retryable(
+ retryFor = [SQLRecoverableException::class],
+ maxAttempts = 5,
+ backoff = Backoff(delay = 100, multiplier = 2.0, maxDelay = 5000, random = true),
+)
+annotation class YdbRetryable
\ No newline at end of file
diff --git a/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/service/SloService.kt b/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/service/SloService.kt
new file mode 100644
index 0000000..b49bd3d
--- /dev/null
+++ b/slo/hibernate/src/main/kotlin/tech/ydb/slo/hibernate/service/SloService.kt
@@ -0,0 +1,37 @@
+package tech.ydb.slo.hibernate.service
+
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.stereotype.Service
+import tech.ydb.slo.hibernate.entity.SloEntity
+import tech.ydb.slo.hibernate.repository.SloEntityRepository
+import tech.ydb.slo.hibernate.retry.YdbRetryable
+import java.time.Instant
+import java.util.Optional
+import java.util.UUID
+import java.util.concurrent.ThreadLocalRandom
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * @author Kirill Kurdyukov
+ */
+@Service
+class SloService {
+ private val id = AtomicInteger(1)
+
+ @Autowired
+ private lateinit var sloEntityRepository: SloEntityRepository
+
+ @YdbRetryable
+ fun save() = sloEntityRepository.save(
+ SloEntity().apply {
+ id = this@SloService.id.getAndIncrement()
+ payloadStr = UUID.randomUUID().toString()
+ payloadDouble = ThreadLocalRandom.current().nextDouble()
+ payloadTimestamp = Instant.now()
+ }
+ )
+
+ @YdbRetryable
+ fun find(): Optional =
+ sloEntityRepository.findById(ThreadLocalRandom.current().nextInt(id.get()))
+}
\ No newline at end of file
diff --git a/slo/hibernate/src/main/resources/application.properties b/slo/hibernate/src/main/resources/application.properties
new file mode 100644
index 0000000..16fd831
--- /dev/null
+++ b/slo/hibernate/src/main/resources/application.properties
@@ -0,0 +1,7 @@
+spring.application.name=hibernate
+spring.datasource.url=jdbc:ydb:grpc://database-sample-grpc:2135/root/database-sample
+spring.jpa.properties.hibernate.dialect=tech.ydb.hibernate.dialect.YdbDialect
+
+spring.datasource.driver-class-name=tech.ydb.jdbc.YdbDriver
+spring.flyway.connect-retries=10
+spring.flyway.connect-retries-interval=1s
\ No newline at end of file
diff --git a/slo/hibernate/src/main/resources/db/migration/V1__create_table.sql b/slo/hibernate/src/main/resources/db/migration/V1__create_table.sql
new file mode 100644
index 0000000..50f4960
--- /dev/null
+++ b/slo/hibernate/src/main/resources/db/migration/V1__create_table.sql
@@ -0,0 +1,8 @@
+CREATE TABLE `slo-hibernate`
+(
+ id Int32,
+ payload_str Text,
+ payload_double Double,
+ payload_timestamp Timestamp,
+ PRIMARY KEY (id)
+)
\ No newline at end of file
diff --git a/slo/pom.xml b/slo/pom.xml
new file mode 100644
index 0000000..fc678f9
--- /dev/null
+++ b/slo/pom.xml
@@ -0,0 +1,85 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.3.3
+
+
+ ydb.tech
+ slo
+ 0.0.1-SNAPSHOT
+ slo
+ pom
+ slo
+
+ 21
+ 1.9.25
+ 2.2.3
+ 1.3.1
+
+
+ hibernate
+
+
+
+ org.jetbrains.kotlin
+ kotlin-reflect
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+
+
+ org.flywaydb
+ flyway-core
+
+
+ tech.ydb.dialects
+ flyway-ydb-dialect
+ 1.0.0-RC0
+
+
+ tech.ydb.jdbc
+ ydb-jdbc-driver
+ ${ydb.jdbc.driver.version}
+
+
+
+
+ io.prometheus
+ prometheus-metrics-core
+ ${prometheus.version}
+
+
+ io.prometheus
+ prometheus-metrics-config
+ ${prometheus.version}
+
+
+ io.prometheus
+ prometheus-metrics-exporter-pushgateway
+ ${prometheus.version}
+
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+
+
+ compile
+ compile
+
+ compile
+
+
+
+
+
+
+