CI/CD Pipelines for Geode

Continuous Integration and Continuous Deployment (CI/CD) pipelines automate the software development lifecycle, from code commit through testing, building, and deployment to production. For database systems like Geode, robust CI/CD practices ensure reliability, maintain quality standards, and enable rapid iteration while preventing regressions that could impact data integrity.

Introduction to CI/CD for Databases

CI/CD for database systems presents unique challenges compared to stateless applications:

  • Data Migration Safety: Schema changes must be backward compatible and reversible
  • Long-Running Tests: Comprehensive database tests may take minutes or hours
  • State Management: Each test run requires clean database state
  • Multi-Client Validation: Polyglot clients (Go, Python, Rust, Zig) need testing
  • Performance Regression Detection: Benchmarks must run consistently
  • Standards Compliance: ISO/IEC 39075:2024 GQL conformance verification

Geode’s CI/CD pipeline addresses these challenges through a comprehensive test suite, automated validation, and careful deployment orchestration.

Geode’s CI/CD Architecture

Pipeline Overview

Geode uses a multi-stage pipeline that validates changes at increasing levels of confidence:

Code Commit → Build → Unit Tests → Integration Tests → Compliance Tests
Performance Benchmarks → Client Tests → Deploy to Staging → Production

Stage 1: Build Verification (30 seconds)

  • Compile server (Zig)
  • Build all client libraries
  • Verify no compilation errors
  • Check code formatting

Stage 2: Unit Testing (2-3 minutes)

  • Core Geode unit tests (1,688 tests)
  • Individual client library tests
  • Mock-free, server-backed testing
  • 97.4% pass rate target

Stage 3: Integration Testing (5-10 minutes)

  • Cross-client test harness
  • Multi-client scenarios
  • Transaction isolation tests
  • Concurrent access tests

Stage 4: Conformance Testing (3-5 minutes)

  • ISO/IEC 39075:2024 conformance profile tests (full GQL)
  • Standards conformance validation (profile-based)
  • Conformance profile gating

Stage 5: Performance Testing (10-20 minutes)

  • Benchmark suite execution
  • Regression detection
  • Resource utilization monitoring
  • Throughput and latency validation

Build Configuration Example

GitHub Actions Workflow (.github/workflows/ci.yml):

name: Geode CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  ZIG_VERSION: 0.1.0
  GO_VERSION: 1.24.0
  PYTHON_VERSION: 3.11
  RUST_VERSION: 1.70

jobs:
  build-server:
    name: Build Geode Server
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v4

      - name: Setup Zig
        uses: goto-bus-stop/setup-zig@v2
        with:
          version: ${{ env.ZIG_VERSION }}

      - name: Build Geode
        working-directory: geode
        run: |
          zig build -Doptimize=ReleaseSafe
          ./zig-out/bin/geode --version          

      - name: Upload Geode Binary
        uses: actions/upload-artifact@v4
        with:
          name: geode-server
          path: geode/zig-out/bin/geode
          retention-days: 7

  unit-tests:
    name: Unit Tests
    needs: build-server
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v4

      - name: Setup Zig
        uses: goto-bus-stop/setup-zig@v2
        with:
          version: ${{ env.ZIG_VERSION }}

      - name: Run Unit Tests
        working-directory: geode
        run: |
          zig build test          

      - name: Run GeodeTestLab Comprehensive
        working-directory: geode
        run: |
          make geodetestlab-comprehensive          

      - name: Generate Coverage Report
        run: |
          zig build test -Dcoverage=true
          # Process coverage data          

  gql-compliance:
    name: GQL Compliance Tests
    needs: build-server
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v4

      - name: Download Geode Binary
        uses: actions/download-artifact@v4
        with:
          name: geode-server
          path: bin

      - name: Make Binary Executable
        run: chmod +x bin/geode

      - name: Start Geode Server
        run: |
          bin/geode serve --listen 0.0.0.0:3141 &
          sleep 5
          # Wait for server ready
          timeout 30 bash -c 'until nc -z localhost 3141; do sleep 1; done'          

      - name: Run GQL Compliance Suite
        working-directory: geode
        run: |
          make gql-compliance-tests
          # Requires see conformance profile          

      - name: Upload Test Results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: gql-compliance-results
          path: geode/test-results/gql-compliance/

  client-tests:
    name: Client Tests (${{ matrix.client }})
    needs: build-server
    runs-on: ubuntu-24.04
    strategy:
      matrix:
        client: [go, python, rust, zig]
    steps:
      - uses: actions/checkout@v4

      - name: Download Geode Binary
        uses: actions/download-artifact@v4
        with:
          name: geode-server
          path: bin

      - name: Start Geode Server
        run: |
          chmod +x bin/geode
          bin/geode serve --listen 0.0.0.0:3141 &
          sleep 5          

      - name: Setup Client Environment
        uses: ./.github/actions/setup-${{ matrix.client }}

      - name: Run Client Tests
        working-directory: geode-client-${{ matrix.client }}
        run: |
          make test          

      - name: Upload Test Results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: client-test-results-${{ matrix.client }}
          path: geode-client-${{ matrix.client }}/test-results/

  integration-tests:
    name: Integration Tests
    needs: [build-server, client-tests]
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v4

      - name: Download Geode Binary
        uses: actions/download-artifact@v4
        with:
          name: geode-server
          path: bin

      - name: Start Geode Server
        run: |
          chmod +x bin/geode
          bin/geode serve --listen 0.0.0.0:3141 &
          sleep 5          

      - name: Setup Test Harness
        working-directory: geode-test-harness
        run: |
          make setup          

      - name: Run Cross-Client Tests
        working-directory: geode-test-harness
        run: |
          make test-all
          make test-all-html          

      - name: Upload Test Report
        uses: actions/upload-artifact@v4
        with:
          name: integration-test-report
          path: geode-test-harness/reports/

  performance-tests:
    name: Performance Benchmarks
    needs: build-server
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v4

      - name: Download Geode Binary
        uses: actions/download-artifact@v4
        with:
          name: geode-server
          path: bin

      - name: Start Geode Server
        run: |
          chmod +x bin/geode
          bin/geode serve --listen 0.0.0.0:3141 &
          sleep 5          

      - name: Run Benchmark Suite
        working-directory: geode
        run: |
          make benchmark          

      - name: Detect Performance Regressions
        run: |
          # Compare against baseline
          python scripts/check-performance-regression.py \
            --baseline benchmarks/baseline.json \
            --current benchmarks/current.json \
            --threshold 10  # 10% regression threshold          

      - name: Upload Benchmark Results
        uses: actions/upload-artifact@v4
        with:
          name: benchmark-results
          path: geode/benchmarks/

  deploy-staging:
    name: Deploy to Staging
    needs: [unit-tests, gql-compliance, integration-tests, performance-tests]
    runs-on: ubuntu-24.04
    if: github.ref == 'refs/heads/main'
    environment:
      name: staging
      url: https://staging.geodedb.com
    steps:
      - uses: actions/checkout@v4

      - name: Download Geode Binary
        uses: actions/download-artifact@v4
        with:
          name: geode-server
          path: bin

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1

      - name: Deploy to ECS
        run: |
          # Update ECS task definition
          aws ecs update-service \
            --cluster geode-staging \
            --service geode-server \
            --force-new-deployment          

      - name: Wait for Deployment
        run: |
          aws ecs wait services-stable \
            --cluster geode-staging \
            --services geode-server          

      - name: Run Smoke Tests
        run: |
          python scripts/smoke-test.py --host staging.geodedb.com:3141          

  deploy-production:
    name: Deploy to Production
    needs: deploy-staging
    runs-on: ubuntu-24.04
    if: github.ref == 'refs/heads/main'
    environment:
      name: production
      url: https://geodedb.com
    steps:
      - uses: actions/checkout@v4

      - name: Download Geode Binary
        uses: actions/download-artifact@v4
        with:
          name: geode-server
          path: bin

      - name: Blue-Green Deployment
        run: |
          # Deploy to green environment
          # Run health checks
          # Switch traffic from blue to green
          # Keep blue as rollback option
          ./scripts/blue-green-deploy.sh \
            --cluster geode-production \
            --new-version ${{ github.sha }}          

Advanced CI/CD Patterns

Parallel Testing Strategy

Geode’s test suite is parallelized for efficiency:

jobs:
  test-matrix:
    name: Test (${{ matrix.os }}, ${{ matrix.zig }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-24.04, macos-14, windows-2022]
        zig: [0.1.0, master]
        exclude:
          # Exclude unstable combinations
          - os: windows-2022
            zig: master
    steps:
      - name: Run Tests
        run: zig build test

Benefits:

  • Tests run in 5-8 minutes instead of 30+ minutes sequentially
  • Early failure detection across platforms
  • Matrix testing validates multiple configurations

Canary Deployments

For production deployments, Geode uses canary releases:

canary-deployment:
  steps:
    - name: Deploy Canary (5% Traffic)
      run: |
        kubectl set image deployment/geode-server \
          geode=geode:${{ github.sha }} \
          -n production

        kubectl patch service geode-lb \
          -p '{"spec":{"selector":{"version":"canary"}}}' \
          --type=merge        

    - name: Monitor Canary
      run: |
        # Watch error rates, latency, throughput
        python scripts/monitor-canary.py \
          --duration 600 \
          --error-threshold 0.1 \
          --latency-p99-threshold 500        

    - name: Promote or Rollback
      run: |
        if [ $? -eq 0 ]; then
          # Promote canary to 100%
          kubectl scale deployment/geode-server-stable --replicas=0
          kubectl scale deployment/geode-server --replicas=10
        else
          # Rollback
          kubectl scale deployment/geode-server --replicas=0
          echo "Canary failed - keeping stable version"
        fi        

Database Migration Testing

Schema migrations require special testing:

migration-tests:
  steps:
    - name: Test Forward Migration
      run: |
        # Start with v0.1.2 schema
        docker run -d --name geode-old geodedb/geode:v0.1.2

        # Load test data
        ./scripts/load-test-data.sh

        # Upgrade to new version
        docker stop geode-old
        docker run -d --name geode-new \
          -v geode-data:/var/lib/geode \
          geodedb/geode:${{ github.sha }}

        # Verify data integrity
        ./scripts/verify-migration.sh        

    - name: Test Rollback
      run: |
        # Rollback to v0.1.2
        docker stop geode-new
        docker run -d --name geode-rollback \
          -v geode-data:/var/lib/geode \
          geodedb/geode:v0.1.2

        # Verify backward compatibility
        ./scripts/verify-rollback.sh        

Quality Gates and Policies

Required Checks

Before merging to main, all checks must pass:

# Branch protection rules
branch_protection:
  required_status_checks:
    - build-server
    - unit-tests
    - gql-compliance
    - client-tests (go)
    - client-tests (python)
    - client-tests (rust)
    - client-tests (zig)
    - integration-tests
    - performance-tests

  required_reviews: 2
  dismiss_stale_reviews: true
  require_code_owner_reviews: true

Test Coverage Requirements

Geode maintains high test coverage standards:

# scripts/check-coverage.py
def check_coverage_requirements(coverage_report):
    requirements = {
        'overall': 90.0,      # 90% overall coverage
        'core': 95.0,         # 95% for core modules
        'security': 100.0,    # 100% for security code
        'parser': 95.0,       # 95% for GQL parser
    }

    for module, threshold in requirements.items():
        actual = coverage_report.get_module_coverage(module)
        if actual < threshold:
            print(f"FAILED: {module} coverage {actual}% < {threshold}%")
            return False

    return True

Performance Regression Detection

Automated performance regression detection:

# scripts/check-performance-regression.py
import json
import sys

def check_regression(baseline, current, threshold=0.10):
    """
    Compare current benchmark results against baseline.
    Fail if performance degrades by more than threshold (10% default).
    """
    regressions = []

    for benchmark in baseline['benchmarks']:
        name = benchmark['name']
        baseline_time = benchmark['mean_time_ms']

        current_bench = next(
            (b for b in current['benchmarks'] if b['name'] == name),
            None
        )

        if not current_bench:
            print(f"WARNING: Benchmark {name} missing from current run")
            continue

        current_time = current_bench['mean_time_ms']
        change = (current_time - baseline_time) / baseline_time

        if change > threshold:
            regressions.append({
                'benchmark': name,
                'baseline': baseline_time,
                'current': current_time,
                'regression': f"{change * 100:.1f}%"
            })

    if regressions:
        print("Performance Regressions Detected:")
        for reg in regressions:
            print(f"  {reg['benchmark']}: {reg['baseline']:.2f}ms → "
                  f"{reg['current']:.2f}ms (+{reg['regression']})")
        return False

    return True

if __name__ == '__main__':
    with open('benchmarks/baseline.json') as f:
        baseline = json.load(f)
    with open('benchmarks/current.json') as f:
        current = json.load(f)

    if not check_regression(baseline, current):
        sys.exit(1)

CI/CD Best Practices for Geode

1. Fast Feedback Loops

Optimize build times:

  • Cache Zig build artifacts (30s → 5s builds)
  • Parallelize independent tests
  • Run smoke tests before full suite
- name: Cache Zig Build
  uses: actions/cache@v4
  with:
    path: |
      ~/.cache/zig
      geode/zig-cache      
    key: ${{ runner.os }}-zig-${{ hashFiles('**/build.zig') }}

2. Reproducible Builds

Pin all dependencies:

# Exact versions, not ranges
env:
  ZIG_VERSION: 0.1.0        # Not "latest"
  GO_VERSION: 1.24.0         # Not "1.24"
  PYTHON_VERSION: 3.11.8     # Not "3.11"

3. Comprehensive Test Data

Test with realistic data:

# Generate realistic test graph
./scripts/generate-test-graph.py \
  --nodes 100000 \
  --relationships 500000 \
  --labels 10 \
  --relationship-types 20

4. Environment Parity

Staging mirrors production:

  • Same instance types (AWS r7g.xlarge)
  • Same Geode configuration
  • Same QUIC settings
  • Same data volume (scaled down)

5. Automated Rollbacks

Automatic rollback on failure:

- name: Health Check
  run: |
    if ! ./scripts/health-check.sh; then
      echo "Health check failed - rolling back"
      kubectl rollout undo deployment/geode-server
      exit 1
    fi    

Monitoring and Observability in CI/CD

Build Monitoring

Track CI/CD metrics:

from prometheus_client import Counter, Histogram

build_duration = Histogram(
    'ci_build_duration_seconds',
    'CI build duration',
    ['stage', 'branch']
)

test_failures = Counter(
    'ci_test_failures_total',
    'CI test failures',
    ['test_suite', 'branch']
)

deployments = Counter(
    'ci_deployments_total',
    'Deployments',
    ['environment', 'status']
)

Deployment Tracking

Track deployments in monitoring systems:

# Send deployment event to monitoring
curl -X POST https://monitoring.geodedb.com/api/deployments \
  -H "Content-Type: application/json" \
  -d '{
    "version": "'$GITHUB_SHA'",
    "environment": "production",
    "timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",
    "triggered_by": "'$GITHUB_ACTOR'",
    "commit_message": "'$COMMIT_MESSAGE'"
  }'

Further Reading

  • CI/CD Best Practices Guide: /docs/operations/ci-cd-best-practices/
  • Deployment Automation: /docs/operations/automated-deployments/
  • Testing Strategy: /docs/development/testing-strategy/
  • Performance Testing: /docs/performance/benchmark-suite/
  • Production Readiness: /docs/operations/production-readiness/

Related Articles