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 + + + + + + +