Flashsales Perf Test #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Flashsales Perf Test | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| flashsale_source_ref: | |
| description: Optional flashsale ref to record with perf results. | |
| required: false | |
| type: string | |
| default: '' | |
| flashsale_source_sha: | |
| description: Optional flashsale sha to record with perf results. | |
| required: false | |
| type: string | |
| default: '' | |
| flashsale_image_tag: | |
| description: Optional deployed flashsale image tag to record with perf results. | |
| required: false | |
| type: string | |
| default: '' | |
| concurrency: | |
| group: flashsales-perf-test-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| packages: write | |
| env: | |
| NAMESPACE: ${{ vars.K8S_NAMESPACE || 'flashsales' }} | |
| PERF_RESULTS_ROOT: ${{ github.workspace }}/flashsale-perf-results | |
| TS_CI_TAGS: ${{ vars.TS_CI_TAGS }} | |
| TS_OAUTH_CLIENT_ID: ${{ secrets.TS_OAUTH_CLIENT_ID }} | |
| TS_OAUTH_SECRET: ${{ secrets.TS_OAUTH_SECRET }} | |
| FLASHSALE_RESULTS_PR_TOKEN: ${{ secrets.HOMELAB_CLOUD_REPO_DISPATCH_TOKEN }} | |
| jobs: | |
| contract: | |
| name: Resolve Flashsale Quality Contract | |
| runs-on: ubuntu-latest | |
| outputs: | |
| perf_cadence_json: ${{ steps.export.outputs.perf_cadence_json }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| - name: Install contract parser dependencies | |
| run: python -m pip install --upgrade pip pyyaml jsonschema | |
| - name: Export flashsale quality contract | |
| id: export | |
| run: | | |
| python3 .github/scripts/export_flashsale_quality_contract.py \ | |
| application/flashsale/release/flashsale-quality-contract.yaml \ | |
| "$GITHUB_OUTPUT" | |
| prepare: | |
| name: Prepare Perf Environment | |
| runs-on: ${{ fromJson(vars.K8S_RUNNER_LABELS_JSON || '["ubuntu-latest"]') }} | |
| needs: | |
| - contract | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Setup Node.js 24 | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '24' | |
| - name: Install kubectl | |
| uses: azure/setup-kubectl@v4 | |
| - name: Install k6 | |
| uses: grafana/setup-k6-action@v1 | |
| - name: Configure private k3s access | |
| uses: ./.github/actions/setup-private-k3s-access | |
| with: | |
| kube_config_data: ${{ secrets.KUBE_CONFIG_DATA }} | |
| k3s_server_url_tailscale: ${{ vars.K3S_SERVER_URL_TAILSCALE }} | |
| ts_oauth_client_id: ${{ env.TS_OAUTH_CLIENT_ID }} | |
| ts_oauth_secret: ${{ env.TS_OAUTH_SECRET }} | |
| ts_ci_tags: ${{ env.TS_CI_TAGS }} | |
| verify_sleep_seconds: "5" | |
| - name: Verify target services | |
| run: | | |
| set -euo pipefail | |
| kubectl -n "$NAMESPACE" get svc flashsales-user-service | |
| kubectl -n "$NAMESPACE" get svc flashsales-product-service | |
| kubectl -n "$NAMESPACE" get svc flashsales-order-service | |
| perf-cadence: | |
| name: Run Flashsale Perf Cadence | |
| runs-on: ${{ fromJson(vars.K8S_RUNNER_LABELS_JSON || '["ubuntu-latest"]') }} | |
| needs: | |
| - contract | |
| - prepare | |
| if: ${{ needs.prepare.result == 'success' }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Resolve perf source metadata | |
| id: source_metadata | |
| run: | | |
| set -euo pipefail | |
| source_ref="${{ github.event.inputs.flashsale_source_ref }}" | |
| source_sha="${{ github.event.inputs.flashsale_source_sha }}" | |
| image_tag="${{ github.event.inputs.flashsale_image_tag }}" | |
| if [ -z "$source_ref" ]; then | |
| source_ref="$(git -C application/flashsale rev-parse --abbrev-ref HEAD)" | |
| if [ "$source_ref" = "HEAD" ]; then | |
| source_ref="${{ github.ref_name }}" | |
| fi | |
| fi | |
| if [ -z "$source_sha" ]; then | |
| source_sha="$(git -C application/flashsale rev-parse HEAD)" | |
| fi | |
| { | |
| echo "source_ref=$source_ref" | |
| echo "source_sha=$source_sha" | |
| echo "image_tag=$image_tag" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Setup Node.js 24 | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '24' | |
| - name: Install kubectl | |
| uses: azure/setup-kubectl@v4 | |
| - name: Install k6 | |
| uses: grafana/setup-k6-action@v1 | |
| - name: Configure private k3s access | |
| uses: ./.github/actions/setup-private-k3s-access | |
| with: | |
| kube_config_data: ${{ secrets.KUBE_CONFIG_DATA }} | |
| k3s_server_url_tailscale: ${{ vars.K3S_SERVER_URL_TAILSCALE }} | |
| ts_oauth_client_id: ${{ env.TS_OAUTH_CLIENT_ID }} | |
| ts_oauth_secret: ${{ env.TS_OAUTH_SECRET }} | |
| ts_ci_tags: ${{ env.TS_CI_TAGS }} | |
| verify_sleep_seconds: "5" | |
| - name: Run flashsale-owned perf cadence | |
| run: | | |
| set -euo pipefail | |
| export KUBECONFIG_PATH="$HOME/.kube/config" | |
| export USE_K8S_PORT_FORWARD="true" | |
| python3 .github/scripts/run_flashsale_perf_cadence.py \ | |
| --lanes-json '${{ needs.contract.outputs.perf_cadence_json }}' \ | |
| --results-root "$PERF_RESULTS_ROOT" | |
| - name: Upload perf results artifact | |
| if: ${{ always() }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: flashsale-perf-results-${{ github.run_id }}-${{ github.run_attempt }} | |
| path: ${{ env.PERF_RESULTS_ROOT }} | |
| if-no-files-found: ignore | |
| - name: Materialize perf results into flashsale repo | |
| if: ${{ always() && env.FLASHSALE_RESULTS_PR_TOKEN != '' }} | |
| id: materialize_results | |
| run: | | |
| set -euo pipefail | |
| if [ ! -f "$PERF_RESULTS_ROOT/manifest.json" ]; then | |
| echo "No perf results manifest found; skipping flashsale PR creation" | |
| echo "results_relative_dir=" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| results_relative_dir="$(python3 .github/scripts/materialize_flashsale_perf_results.py \ | |
| --results-dir "$PERF_RESULTS_ROOT" \ | |
| --flashsale-dir application/flashsale \ | |
| --workflow-name "Flashsales Perf Test" \ | |
| --run-id "${{ github.run_id }}" \ | |
| --run-attempt "${{ github.run_attempt }}" \ | |
| --source-ref "${{ steps.source_metadata.outputs.source_ref }}" \ | |
| --source-sha "${{ steps.source_metadata.outputs.source_sha }}" \ | |
| --image-tag "${{ steps.source_metadata.outputs.image_tag }}")" | |
| echo "results_relative_dir=$results_relative_dir" >> "$GITHUB_OUTPUT" | |
| - name: Create flashsale perf results PR | |
| if: ${{ always() && env.FLASHSALE_RESULTS_PR_TOKEN != '' && steps.materialize_results.outputs.results_relative_dir != '' }} | |
| env: | |
| GH_TOKEN: ${{ env.FLASHSALE_RESULTS_PR_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| branch_name="perf-results/run-${{ github.run_id }}-attempt-${{ github.run_attempt }}" | |
| pr_title="perf: record run ${{ github.run_id }} attempt ${{ github.run_attempt }}" | |
| pr_body="$(mktemp)" | |
| cat > "$pr_body" <<EOF | |
| Record flashsale perf results from GitHub Actions. | |
| - Workflow: Flashsales Perf Test | |
| - Run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| - Attempt: ${{ github.run_attempt }} | |
| - Flashsale ref: ${{ steps.source_metadata.outputs.source_ref }} | |
| - Flashsale sha: ${{ steps.source_metadata.outputs.source_sha }} | |
| - Image tag: ${{ steps.source_metadata.outputs.image_tag }} | |
| - Results path: \`${{ steps.materialize_results.outputs.results_relative_dir }}\` | |
| EOF | |
| git -C application/flashsale config user.name "github-actions[bot]" | |
| git -C application/flashsale config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git -C application/flashsale remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/jingyi-zhao-01/flashsale.git" | |
| git -C application/flashsale checkout -B "$branch_name" | |
| git -C application/flashsale add "${{ steps.materialize_results.outputs.results_relative_dir }}" | |
| git -C application/flashsale commit -m "$pr_title" || { | |
| echo "No perf result changes to commit; skipping PR creation" | |
| exit 0 | |
| } | |
| git -C application/flashsale push --force-with-lease origin "$branch_name" | |
| gh pr create \ | |
| --repo jingyi-zhao-01/flashsale \ | |
| --base main \ | |
| --head "$branch_name" \ | |
| --title "$pr_title" \ | |
| --body-file "$pr_body" | |
| notify-discord: | |
| name: Notify Discord | |
| needs: | |
| - contract | |
| - prepare | |
| - perf-cadence | |
| if: ${{ always() }} | |
| runs-on: ubuntu-latest | |
| continue-on-error: true | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| continue-on-error: true | |
| - name: Send Discord notification | |
| continue-on-error: true | |
| env: | |
| AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| AWS_REGION: ${{ vars.AWS_REGION }} | |
| DISCORD_WEBHOOK_SSM_NAME: ${{ vars.DISCORD_WEBHOOK_SSM_NAME || '/codex/discord-webhook' }} | |
| WORKFLOW_NAME: Flashsales Perf Test | |
| NEEDS_JSON: ${{ toJson(needs) }} | |
| run: bash .github/scripts/notify-discord.sh |