name: Pull request benchmark on: pull_request: permissions: contents: read pull-requests: write concurrency: group: pr-benchmark-${{ github.event.pull_request.number }} cancel-in-progress: true jobs: benchmark: name: Native SQLite backfill runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Check out code uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 with: version: 10.30.1 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 22.14 cache: 'pnpm' - name: Install dependencies run: pnpm install --frozen-lockfile - name: Build Contrail run: pnpm --filter @atmo-dev/contrail build - name: Run benchmark run: >- pnpm bench --backend sqlite --config calendar-records-only.config.json --concurrency 100 --pds-concurrency 20 --dids-per-pds 3 --max-attempts 1 - name: Publish benchmark summary if: always() shell: bash run: | result="$(find apps/benchmark/results -type f -name 'calendar-records-only-sqlite-*.json' -print -quit)" if [[ -z "$result" ]]; then printf '## Native SQLite benchmark\n\nThe benchmark did not produce a result.\n' > "$RUNNER_TEMP/benchmark-comment.md" cat "$RUNNER_TEMP/benchmark-comment.md" >> "$GITHUB_STEP_SUMMARY" exit 0 fi RESULT_PATH="$result" node --input-type=module <<'NODE' import { appendFileSync, readFileSync, writeFileSync } from "node:fs"; import { basename, join } from "node:path"; const result = JSON.parse(readFileSync(process.env.RESULT_PATH, "utf8")); const seconds = (milliseconds) => `${(Number(milliseconds) / 1000).toFixed(2)} s`; const integer = (value) => Number(value).toLocaleString("en-US"); const decimal = (value) => Number(value).toFixed(2); const accounts = result.backfill?.accounts ?? {}; const lines = [ "## Native SQLite benchmark", "", "| Metric | Result |", "| --- | ---: |", `| Total time | ${seconds(result.timings_ms.total)} |`, `| Backfill time | ${seconds(result.timings_ms.backfill)} |`, `| Indexed records | ${integer(result.indexed_records)} |`, `| Accepted records/s | ${decimal(result.throughput.accepted_records_per_second)} |`, `| Indexed records/s | ${decimal(result.throughput.indexed_records_per_second)} |`, `| Complete accounts | ${integer(accounts.complete ?? 0)} |`, `| Retrying accounts | ${integer(accounts.retrying ?? 0)} |`, "", `Runtime: Node ${result.runtime.node}, SQLite ${result.runtime.sqlite ?? "unknown"}`, "", `Artifact source: \`${basename(process.env.RESULT_PATH)}\``, ]; const report = `${lines.join("\n")}\n`; appendFileSync(process.env.GITHUB_STEP_SUMMARY, report); writeFileSync(join(process.env.RUNNER_TEMP, "benchmark-comment.md"), report); NODE - name: Comment on pull request if: always() && github.event.pull_request.head.repo.full_name == github.repository uses: actions/github-script@v7 with: script: | const { readFileSync } = require("node:fs"); const { join } = require("node:path"); const marker = ""; const report = readFileSync( join(process.env.RUNNER_TEMP, "benchmark-comment.md"), "utf8", ); const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; const body = `${marker}\n${report}\n[View workflow run](${runUrl})`; const comments = await github.paginate( github.rest.issues.listComments, { owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, per_page: 100, }, ); const existing = comments.find( (comment) => comment.user?.login === "github-actions[bot]" && comment.body?.includes(marker), ); if (existing) { await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: existing.id, body, }); } else { await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body, }); } - name: Upload benchmark result if: always() uses: actions/upload-artifact@v4 with: name: benchmark-pr-${{ github.event.pull_request.number }}-${{ github.run_attempt }} path: apps/benchmark/results/*.json if-no-files-found: ignore retention-days: 14