Skip to content

Add parallel hook execution with Web Workers #6

@drernie

Description

@drernie

Summary

Enable parallel execution of independent hooks using Deno Workers to significantly speed up pre-commit/pre-push operations.

Motivation

Current implementation runs hooks sequentially:

  • Slow for projects with multiple hooks
  • Wastes time when hooks are independent
  • Poor developer experience (waiting for each hook)

Example: fmt + lint + test could run in ~3 seconds instead of ~9 seconds.

Proposed Solution

hooks:
  pre-commit:
    - id: fmt
      run: deno-fmt
      parallel: true  # Can run in parallel
      
    - id: lint
      run: deno-lint
      parallel: true  # Can run in parallel
      
    - id: test
      run: deno-test
      parallel: false  # Must run after fmt/lint
      depends_on: [fmt, lint]

Implementation Strategy

  1. Build dependency graph from depends_on fields
  2. Identify hooks that can run in parallel (no dependencies)
  3. Use Deno Workers to execute independent hooks concurrently
  4. Wait for dependencies before running dependent hooks
  5. Aggregate results and report
interface HookConfig {
  id: string;
  run: string;
  parallel?: boolean;  // Default: true
  depends_on?: string[];  // IDs of hooks that must complete first
}

async function executeHooksInParallel(hooks: HookConfig[]): Promise<HookResult[]> {
  const graph = buildDependencyGraph(hooks);
  const results: HookResult[] = [];
  
  for (const batch of graph.batches) {
    // Execute batch in parallel
    const batchResults = await Promise.all(
      batch.map(hook => executeInWorker(hook))
    );
    results.push(...batchResults);
    
    // Stop if any hook failed
    if (batchResults.some(r => !r.success)) {
      break;
    }
  }
  
  return results;
}

Benefits

  • 3x faster pre-commit hooks in typical projects
  • ✅ Better developer experience (less waiting)
  • Leverages Deno's Web Workers - native parallelism
  • ✅ Smart dependency handling
  • ✅ Graceful degradation (falls back to sequential if needed)

Configuration Examples

Simple parallel:

hooks:
  pre-commit:
    - id: fmt
      run: deno-fmt
    - id: lint
      run: deno-lint
    # Both run in parallel by default

With dependencies:

hooks:
  pre-commit:
    - id: fmt
      run: deno-fmt
      
    - id: lint
      run: deno-lint
      
    - id: test
      run: deno-test
      depends_on: [fmt, lint]  # Runs after fmt and lint complete
      
    - id: build
      run: deno task build
      depends_on: [test]  # Runs after test completes

Opt-out of parallel:

hooks:
  pre-commit:
    - id: database-migration
      run: ./migrate.ts
      parallel: false  # Always run sequentially

Files to Modify

  • src/run.ts - Orchestrate parallel execution
  • src/executor.ts - Support Worker-based execution
  • src/hook.ts - Add parallel and depends_on to types
  • src/config.ts - Parse new configuration options

Priority

MEDIUM - High impact on developer experience, moderate complexity

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions