diff --git a/.github/workflows/slo.yml b/.github/workflows/slo.yml new file mode 100644 index 0000000000..2d582a7a8c --- /dev/null +++ b/.github/workflows/slo.yml @@ -0,0 +1,273 @@ +name: SLO + +on: + pull_request: + types: [opened, reopened, synchronize] + branches: + - main + workflow_dispatch: + inputs: + github_issue: + description: "GitHub issue number where the SLO results will be reported" + required: true + baseline_ref: + description: "Baseline commit/branch/tag to compare against (leave empty to auto-detect merge-base with main)" + required: false + slo_workload_duration_seconds: + description: "Duration of the SLO workload in seconds" + required: false + default: "600" + slo_workload_read_max_rps: + description: "Maximum read RPS for the SLO workload" + required: false + default: "1000" + slo_workload_write_max_rps: + description: "Maximum write RPS for the SLO workload" + required: false + default: "100" + +jobs: + ydb-slo-action: + name: Run YDB SLO Tests + runs-on: ubuntu-latest + + strategy: + matrix: + include: + - workload: table + + concurrency: + group: slo-${{ github.ref }} + cancel-in-progress: true + + steps: + - name: Install dependencies + run: | + YQ_VERSION=v4.48.2 + BUILDX_VERSION=0.30.1 + COMPOSE_VERSION=2.40.3 + + sudo curl -L https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64 -o /usr/local/bin/yq && \ + sudo chmod +x /usr/local/bin/yq + + echo "Updating Docker plugins..." + sudo mkdir -p /usr/local/lib/docker/cli-plugins + + echo "Installing Docker Buildx ${BUILDX_VERSION}..." + sudo curl -fLo /usr/local/lib/docker/cli-plugins/docker-buildx \ + "https://github.com/docker/buildx/releases/download/v${BUILDX_VERSION}/buildx-v${BUILDX_VERSION}.linux-amd64" + sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx + + echo "Installing Docker Compose ${COMPOSE_VERSION}..." + sudo curl -fLo /usr/local/lib/docker/cli-plugins/docker-compose \ + "https://github.com/docker/compose/releases/download/v${COMPOSE_VERSION}/docker-compose-linux-x86_64" + sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose + + echo "Installed versions:" + yq --version + docker --version + docker buildx version + docker compose version + + - name: Checkout current version + uses: actions/checkout@v5 + with: + path: current + fetch-depth: 0 + submodules: true + + - name: Determine baseline commit + id: baseline + run: | + cd current + if [[ -n "${{ inputs.baseline_ref }}" ]]; then + BASELINE="${{ inputs.baseline_ref }}" + else + BASELINE=$(git merge-base HEAD origin/main) + fi + echo "sha=$BASELINE" >> $GITHUB_OUTPUT + + # Try to determine a human-readable ref name for baseline + # Check if baseline is on main + if git merge-base --is-ancestor $BASELINE origin/main && \ + [ "$(git rev-parse origin/main)" = "$BASELINE" ]; then + BASELINE_REF="main" + else + # Try to find a branch containing this commit + BRANCH=$(git branch -r --contains $BASELINE | grep -v HEAD | head -1 | sed 's/.*\///' || echo "") + if [ -n "$BRANCH" ]; then + BASELINE_REF="${BRANCH}@${BASELINE:0:7}" + else + BASELINE_REF="${BASELINE:0:7}" + fi + fi + echo "ref=$BASELINE_REF" >> $GITHUB_OUTPUT + + - name: Checkout baseline version + uses: actions/checkout@v5 + with: + ref: ${{ steps.baseline.outputs.sha }} + path: baseline + fetch-depth: 1 + submodules: true + + - name: Build Workload Image + run: | + echo "Cleaning up Docker system before builds..." + docker system prune -af --volumes + docker builder prune -af + df -h + + # Build current version + if [ -f "$GITHUB_WORKSPACE/current/tests/slo_workloads/Dockerfile" ]; then + echo "Building current app image..." + cd "$GITHUB_WORKSPACE/current" + + # Use SLO-specific .dockerignore + cp tests/slo_workloads/.dockerignore .dockerignore + + docker build -t ydb-app-current \ + --build-arg REF="${{ github.head_ref || github.ref_name }}" \ + -f tests/slo_workloads/Dockerfile . + + # Clean up .dockerignore + rm -f .dockerignore + else + echo "No current app Dockerfile found" + exit 1 + fi + + docker system prune -f --volumes + docker builder prune -af + + # Build baseline version + if [ -f "$GITHUB_WORKSPACE/baseline/tests/slo_workloads/Dockerfile" ]; then + echo "Building baseline app image..." + cd "$GITHUB_WORKSPACE/baseline" + + # Use SLO-specific .dockerignore + cp tests/slo_workloads/.dockerignore .dockerignore + + docker build -t ydb-app-baseline \ + --build-arg REF="${{ steps.baseline.outputs.ref }}" \ + -f tests/slo_workloads/Dockerfile . + + # Clean up .dockerignore + rm -f .dockerignore + else + echo "No baseline app Dockerfile found" + exit 1 + fi + + docker system prune -f --volumes + docker builder prune -af + + echo "Final disk space after builds:" + df -h + + - name: Initialize YDB SLO + uses: ydb-platform/ydb-slo-action/init@main + with: + github_issue: ${{ github.event.inputs.github_issue }} + github_token: ${{ secrets.GITHUB_TOKEN }} + workload_name: ${{ matrix.workload }} + workload_current_ref: ${{ github.head_ref || github.ref_name }} + workload_baseline_ref: ${{ steps.baseline.outputs.ref }} + + - name: Prepare SLO Database + run: | + echo "Preparing SLO database..." + docker run --rm --network ydb_ydb-net \ + --add-host "ydb:172.28.0.11" \ + --add-host "ydb:172.28.0.12" \ + --add-host "ydb:172.28.0.13" \ + --add-host "ydb:172.28.0.99" \ + ydb-app-current --connection-string grpc://ydb:2136/?database=/Root/testdb create --dont-push + + - name: Run SLO Tests (parallel) + timeout-minutes: 15 + run: | + DURATION=${{ inputs.slo_workload_duration_seconds || 600 }} + READ_RPS=${{ inputs.slo_workload_read_max_rps || 1000 }} + WRITE_RPS=${{ inputs.slo_workload_write_max_rps || 100 }} + + ARGS="--connection-string grpc://ydb:2136/?database=/Root/testdb run \ + --metrics-push-url http://prometheus:9090/api/v1/otlp/v1/metrics \ + --time $DURATION \ + --read-rps $READ_RPS \ + --write-rps $WRITE_RPS \ + --read-timeout 100 \ + --write-timeout 100" + + echo "Starting ydb-app-current..." + docker run -d \ + --name ydb-app-current \ + --network ydb_ydb-net \ + --add-host "ydb:172.28.0.11" \ + --add-host "ydb:172.28.0.12" \ + --add-host "ydb:172.28.0.13" \ + --add-host "ydb:172.28.0.99" \ + ydb-app-current $ARGS + + echo "Starting ydb-app-baseline..." + docker run -d \ + --name ydb-app-baseline \ + --network ydb_ydb-net \ + --add-host "ydb:172.28.0.11" \ + --add-host "ydb:172.28.0.12" \ + --add-host "ydb:172.28.0.13" \ + --add-host "ydb:172.28.0.99" \ + ydb-app-baseline $ARGS + + # Show initial logs + echo "" + echo "==================== INITIAL CURRENT LOGS ====================" + docker logs -n 15 ydb-app-current 2>&1 || echo "No current container" + echo "" + echo "==================== INITIAL BASELINE LOGS ====================" + docker logs -n 15 ydb-app-baseline 2>&1 || echo "No baseline container" + echo "" + + # Wait for workloads to complete + echo "Waiting for workloads to complete (${DURATION}s)..." + sleep ${DURATION} + + # Stop containers after workload duration and wait for graceful shutdown + echo "Stopping containers after ${DURATION}s..." + docker stop --timeout=30 ydb-app-current ydb-app-baseline 2>&1 || true + + # Force kill if still running + docker kill ydb-app-current ydb-app-baseline 2>&1 || true + + # Check exit codes + CURRENT_EXIT=$(docker inspect ydb-app-current --format='{{.State.ExitCode}}' 2>/dev/null || echo "1") + BASELINE_EXIT=$(docker inspect ydb-app-baseline --format='{{.State.ExitCode}}' 2>/dev/null || echo "0") + + echo "Current container exit code: $CURRENT_EXIT" + echo "Baseline container exit code: $BASELINE_EXIT" + + # Show final logs + echo "" + echo "==================== FINAL CURRENT LOGS ====================" + docker logs -n 15 ydb-app-current 2>&1 || echo "No current container" + echo "" + echo "==================== FINAL BASELINE LOGS ====================" + docker logs -n 15 ydb-app-baseline 2>&1 || echo "No baseline container" + echo "" + + echo "SUCCESS: Workloads completed successfully" + + - if: always() + name: Store logs + run: | + docker logs ydb-app-current > current.log 2>&1 || echo "No current container" + docker logs ydb-app-baseline > baseline.log 2>&1 || echo "No baseline container" + + - if: always() + uses: actions/upload-artifact@v4 + with: + name: ${{matrix.workload}}-slo-cpp-sdk-logs + path: | + ./current.log + ./baseline.log + retention-days: 1 diff --git a/.github/workflows/slo_report.yml b/.github/workflows/slo_report.yml new file mode 100644 index 0000000000..e06301abac --- /dev/null +++ b/.github/workflows/slo_report.yml @@ -0,0 +1,23 @@ +name: SLO Report + +on: + workflow_run: + workflows: ["SLO CPP SDK"] + types: + - completed + +jobs: + ydb-slo-action-report: + runs-on: ubuntu-latest + name: Publish YDB SLO Report + permissions: + checks: write + contents: read + pull-requests: write + if: github.event.workflow_run.conclusion == 'success' + steps: + - name: Publish YDB SLO Report + uses: ydb-platform/ydb-slo-action/report@main + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + github_run_id: ${{ github.event.workflow_run.id }} diff --git a/tests/slo_workloads/.dockerignore b/tests/slo_workloads/.dockerignore index b0b001ba35..9e958bd1bf 100644 --- a/tests/slo_workloads/.dockerignore +++ b/tests/slo_workloads/.dockerignore @@ -5,12 +5,17 @@ .gitattributes # IDE and editor files -.vscode -.idea +.idea/ +.vscode/ +.cache/ +.cursor/ +.cursorrules *.swp *.swo -*~ .DS_Store +*.dSYM +.clangd +compile_commands.json # Build artifacts and cache *.o @@ -29,7 +34,6 @@ node_modules/ # Documentation *.md docs/ -*.txt !requirements.txt # CI/CD @@ -37,31 +41,8 @@ docs/ .travis.yml azure-pipelines.yml -# Test files -*_test.cpp -*_test.py -*_ut.cpp -test_* -tests/ -!ydb/public/sdk/cpp/tests/slo_workloads/ - # Large directories not needed for SDK builds ydb/core/ ydb/apps/ ydb/services/ ydb/tools/ - -# Keep only what's needed (specified in Dockerfile COPY commands): -# - build/ -# - certs/ -# - contrib/ -# - library/cpp/ -# - tools/ -# - util/ -# - ydb/library/yverify_stream/ -# - ydb/public/api/ -# - ydb/public/lib/protobuf/ -# - ydb/public/lib/validation/ -# - ydb/public/sdk/cpp/ -# - ya - diff --git a/tests/slo_workloads/Dockerfile b/tests/slo_workloads/Dockerfile index 65d9c7693b..ab909c7268 100644 --- a/tests/slo_workloads/Dockerfile +++ b/tests/slo_workloads/Dockerfile @@ -1,6 +1,7 @@ FROM ubuntu:22.04 ARG PRESET=release-test-clang +ARG REF=unknown # Install software-properties-common for add-apt-repository RUN apt-get -y update && apt-get -y install software-properties-common && add-apt-repository ppa:ubuntu-toolchain-r/test @@ -119,7 +120,7 @@ COPY . /ydb-cpp-sdk WORKDIR /ydb-cpp-sdk RUN rm -rf build -RUN cmake --preset ${PRESET} +RUN ls -la && cmake -DSLO_BRANCH_REF=${REF} --preset ${PRESET} RUN cmake --build --preset default --target slo-key-value ENTRYPOINT ["./build/tests/slo_workloads/key_value/slo-key-value"] diff --git a/tests/slo_workloads/utils/CMakeLists.txt b/tests/slo_workloads/utils/CMakeLists.txt index 533738db6b..99de2d72bd 100644 --- a/tests/slo_workloads/utils/CMakeLists.txt +++ b/tests/slo_workloads/utils/CMakeLists.txt @@ -9,6 +9,10 @@ target_link_libraries(slo-utils PUBLIC opentelemetry-cpp::otlp_http_metric_exporter ) +if (SLO_BRANCH_REF) + target_compile_definitions(slo-utils PRIVATE REF="${SLO_BRANCH_REF}") +endif() + target_sources(slo-utils PRIVATE executor.cpp generator.cpp