π Replace P95 Latency progress bar with interactive sparkline chart #23
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: Performance Benchmarking | |
| on: | |
| # Run on pull requests to main branches | |
| pull_request: | |
| branches: [ main, testing, develop ] | |
| paths-ignore: | |
| - 'docs/**' | |
| - '*.md' | |
| - 'archive/**' | |
| - 'examples/**' | |
| # Run on pushes to main branches | |
| push: | |
| branches: [ main, testing, develop ] | |
| paths-ignore: | |
| - 'docs/**' | |
| - '*.md' | |
| - 'archive/**' | |
| - 'examples/**' | |
| # Allow manual triggering | |
| workflow_dispatch: | |
| inputs: | |
| environment: | |
| description: 'Environment to benchmark' | |
| required: true | |
| default: 'testing' | |
| type: choice | |
| options: | |
| - development | |
| - testing | |
| - staging | |
| update_baseline: | |
| description: 'Update performance baseline' | |
| required: false | |
| default: false | |
| type: boolean | |
| env: | |
| PYTHON_VERSION: '3.11' | |
| jobs: | |
| performance-benchmarks: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| environment: | |
| - ${{ github.event.inputs.environment || 'testing' }} | |
| services: | |
| postgres: | |
| image: pgvector/pgvector:pg16 | |
| env: | |
| POSTGRES_DB: second_brain_test | |
| POSTGRES_USER: postgres | |
| POSTGRES_PASSWORD: postgres | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432:5432 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements.txt | |
| pip install psutil pyyaml pytest httpx | |
| - name: Setup database | |
| run: | | |
| python -c " | |
| import asyncio | |
| import asyncpg | |
| async def setup(): | |
| conn = await asyncpg.connect( | |
| 'postgresql://postgres:postgres@localhost:5432/second_brain_test' | |
| ) | |
| await conn.execute('CREATE EXTENSION IF NOT EXISTS vector;') | |
| await conn.close() | |
| asyncio.run(setup()) | |
| " | |
| env: | |
| DATABASE_URL: postgresql://postgres:postgres@localhost:5432/second_brain_test | |
| - name: Start Second Brain server | |
| run: | | |
| export DATABASE_URL="postgresql://postgres:postgres@localhost:5432/second_brain_test" | |
| export OPENAI_API_KEY="test-key" | |
| export API_TOKENS="test-token" | |
| # Determine port based on environment | |
| case "${{ matrix.environment }}" in | |
| "development") PORT=8000 ;; | |
| "testing") PORT=8001 ;; | |
| "staging") PORT=8002 ;; | |
| *) PORT=8000 ;; | |
| esac | |
| # Start server in background | |
| python -m uvicorn app.main:app --host 0.0.0.0 --port $PORT & | |
| SERVER_PID=$! | |
| echo "SERVER_PID=$SERVER_PID" >> $GITHUB_ENV | |
| echo "SERVER_PORT=$PORT" >> $GITHUB_ENV | |
| # Wait for server to start | |
| echo "Waiting for server to start on port $PORT..." | |
| for i in {1..30}; do | |
| if curl -f http://localhost:$PORT/health >/dev/null 2>&1; then | |
| echo "Server started successfully" | |
| break | |
| fi | |
| if [ $i -eq 30 ]; then | |
| echo "Server failed to start" | |
| exit 1 | |
| fi | |
| sleep 2 | |
| done | |
| - name: Run performance benchmarks | |
| run: | | |
| # Update configuration for CI environment | |
| python -c " | |
| import yaml | |
| with open('performance_config.yml', 'r') as f: | |
| config = yaml.safe_load(f) | |
| # Override URL for testing | |
| config['environments']['${{ matrix.environment }}']['url'] = 'http://localhost:${{ env.SERVER_PORT }}' | |
| config['environments']['${{ matrix.environment }}']['verify_ssl'] = False | |
| # Enable appropriate tests for CI | |
| if '${{ matrix.environment }}' != 'production': | |
| config['benchmarks']['concurrent_load']['concurrent_requests'] = 20 # Reduced for CI | |
| config['benchmarks']['system_resources']['monitoring_duration'] = 10 # Reduced for CI | |
| with open('performance_config.yml', 'w') as f: | |
| yaml.dump(config, f) | |
| " | |
| # Run the automated performance benchmark | |
| python scripts/performance_automation.py ${{ matrix.environment }} \ | |
| ${{ github.event.inputs.update_baseline == 'true' && '--update-baseline' || '' }} | |
| - name: Upload performance results | |
| uses: actions/upload-artifact@v3 | |
| if: always() | |
| with: | |
| name: performance-results-${{ matrix.environment }} | |
| path: | | |
| results/performance/${{ matrix.environment }}/*.json | |
| results/performance/${{ matrix.environment }}/*.md | |
| retention-days: 30 | |
| - name: Comment performance results on PR | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v6 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| // Find the latest markdown report | |
| const resultsDir = `results/performance/${{ matrix.environment }}`; | |
| const files = fs.readdirSync(resultsDir) | |
| .filter(f => f.endsWith('.md') && f.includes('automation_report')) | |
| .sort() | |
| .reverse(); | |
| if (files.length === 0) { | |
| console.log('No markdown report found'); | |
| return; | |
| } | |
| const reportPath = path.join(resultsDir, files[0]); | |
| const reportContent = fs.readFileSync(reportPath, 'utf8'); | |
| // Create or update comment | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const botComment = comments.find(comment => | |
| comment.user.type === 'Bot' && | |
| comment.body.includes('Performance Benchmark Report') | |
| ); | |
| const commentBody = `## π Performance Benchmark Report - ${{ matrix.environment }} | |
| ${reportContent} | |
| <details> | |
| <summary>π View Detailed Results</summary> | |
| Download the detailed performance artifacts for complete analysis. | |
| </details> | |
| --- | |
| *This comment was automatically generated by the Performance Benchmarking workflow.*`; | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: commentBody | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: commentBody | |
| }); | |
| } | |
| - name: Check performance gate | |
| run: | | |
| # Check the exit code from performance automation | |
| # It should have already failed if performance was below threshold | |
| echo "β Performance benchmarks completed" | |
| # Parse the latest JSON report for additional checks | |
| LATEST_REPORT=$(ls -t results/performance/${{ matrix.environment }}/automation_report_*.json | head -n1) | |
| if [ -f "$LATEST_REPORT" ]; then | |
| echo "π Analyzing performance report: $LATEST_REPORT" | |
| # Extract key metrics using Python | |
| python -c " | |
| import json | |
| import sys | |
| with open('$LATEST_REPORT', 'r') as f: | |
| report = json.load(f) | |
| ci_status = report['ci_cd']['ci_status'] | |
| success_rate = report['ci_cd']['success_rate'] | |
| critical_issues = len(report['ci_cd']['critical_issues']) | |
| regressions = report['ci_cd']['regressions_count'] | |
| print(f'CI Status: {ci_status}') | |
| print(f'Success Rate: {success_rate:.1f}%') | |
| print(f'Critical Issues: {critical_issues}') | |
| print(f'Regressions: {regressions}') | |
| if ci_status == 'FAIL': | |
| print('β Performance benchmarks failed') | |
| sys.exit(1) | |
| elif critical_issues > 0: | |
| print('β οΈ Critical performance issues detected') | |
| sys.exit(1) | |
| else: | |
| print('β Performance benchmarks passed') | |
| " | |
| else | |
| echo "β οΈ No performance report found" | |
| exit 1 | |
| fi | |
| - name: Stop server | |
| if: always() | |
| run: | | |
| if [ ! -z "$SERVER_PID" ]; then | |
| kill $SERVER_PID || true | |
| fi | |
| # Job to run comprehensive performance analysis | |
| performance-analysis: | |
| runs-on: ubuntu-latest | |
| needs: performance-benchmarks | |
| if: always() | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Download all performance artifacts | |
| uses: actions/download-artifact@v3 | |
| with: | |
| path: artifacts/ | |
| - name: Analyze performance trends | |
| run: | | |
| echo "π Analyzing performance trends..." | |
| # This could be enhanced to: | |
| # 1. Compare performance across different environments | |
| # 2. Generate trend reports over time | |
| # 3. Create performance dashboards | |
| # 4. Send notifications for significant changes | |
| find artifacts/ -name "*.json" -type f | while read file; do | |
| echo "Found performance report: $file" | |
| # Basic analysis could be added here | |
| done | |
| - name: Generate performance summary | |
| run: | | |
| echo "## π Performance Summary" > performance-summary.md | |
| echo "" >> performance-summary.md | |
| echo "Performance benchmarks completed for all environments:" >> performance-summary.md | |
| echo "" >> performance-summary.md | |
| find artifacts/ -name "automation_report_*.md" -type f | while read file; do | |
| env_name=$(echo "$file" | sed -n 's/.*performance-results-\([^/]*\).*/\1/p') | |
| echo "- **$env_name**: [View Report]($file)" >> performance-summary.md | |
| done | |
| cat performance-summary.md | |
| - name: Upload combined results | |
| uses: actions/upload-artifact@v3 | |
| with: | |
| name: performance-analysis | |
| path: | | |
| performance-summary.md | |
| artifacts/ | |
| retention-days: 30 |