← ドキュメント一覧/アーキテクチャ

並行実行アーキテクチャ

並行実行アーキテクチャ

概要: 複数のIssue/タスクを同時並行で実行するシステムアーキテクチャです。DAG(有向非巡回グラフ)による依存関係管理、Git Worktreeによるブランチ分離、バッティング回避機構により、効率的な並列作業を実現します。

対象読者: アーキテクト / 実装者 所要時間: 15分 前提知識: Agent階層システム


設計原則

並行実行システムは以下の5原則に基づいて設計されています:

  1. Claude Code Task Tool 必須: すべてのタスクは Claude Code の Task tool を使用
  2. 衝突回避: Git マージコンフリクトと作業の重複を防止
  3. 透明性: すべてのワーカーの活動状況をリアルタイムで可視化
  4. スケーラビリティ: 3人以上のワーカーが同時作業可能
  5. 監査可能性: すべての並列作業活動を記録

システムアーキテクチャ

レイヤー構成

┌─────────────────────────────────────────────────────────┐
│              Worker Interface Layer                      │
│  (Human Developers + AI Agents)                         │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│         Task Orchestration Layer                         │
│  • Task Queue Management                                 │
│  • Worker Registration & Tracking                        │
│  • Claude Code Task Tool Wrapper                         │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│         Coordination Layer                               │
│  • Task Claim/Release Protocol                           │
│  • Conflict Detection & Prevention                       │
│  • Progress Monitoring                                   │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│         Git Workflow Layer                               │
│  • Worktree Management                                   │
│  • Branch Isolation                                      │
│  • Merge Coordination                                    │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│         Storage & State Layer                            │
│  • GitHub Projects V2 (Task Board)                       │
│  • GitHub Repository (Code)                              │
│  • Lock Files (.task-locks/)                             │
└─────────────────────────────────────────────────────────┘

Task Orchestration Layer

TaskOrchestrator

タスクキューの管理とワーカーへの割り当てを担当。

// agents/coordination/TaskOrchestrator.ts
class TaskOrchestrator {
  private queue: PriorityQueue<Task>;
  private activeWorkers: Map<WorkerId, WorkerState>;

  async enqueueTask(task: Task): Promise<void> {
    // タスクをキューに追加(優先度順)
    this.queue.enqueue(task, task.priority);
  }

  async assignTask(workerId: WorkerId): Promise<Task | null> {
    // ワーカーに適切なタスクを割り当て
    const availableTasks = await this.getAvailableTasks(workerId);
    return availableTasks[0] || null;
  }

  async getAvailableTasks(workerId: WorkerId): Promise<Task[]> {
    // 依存関係とファイル競合を考慮
    const worker = this.activeWorkers.get(workerId);
    return this.queue.filter(task =>
      this.canAssign(task, worker)
    );
  }
}

Task構造

interface Task {
  id: string;
  type: 'issue' | 'pr' | 'refactor' | 'test' | 'doc';
  priority: 1 | 2 | 3 | 4 | 5; // 1 = highest
  dependencies: string[]; // task IDs
  estimatedDuration: number; // minutes
  requiredSkills: string[];
  assignedTo?: WorkerId;
  status: 'pending' | 'claimed' | 'in_progress' | 'completed' | 'failed';
  metadata: {
    issueNumber?: number;
    branchName?: string;
    files: string[]; // Files this task will modify
  };
}

DAG(有向非巡回グラフ)による依存関係管理

DAG構築

async buildDAG(tasks: Task[]): Promise<DAG> {
  // 1. ノード作成
  const nodes = tasks.map(task => ({
    id: task.id,
    task
  }));

  // 2. エッジ作成(依存関係)
  const edges: Edge[] = [];
  for (const task of tasks) {
    for (const depId of task.dependencies) {
      edges.push({ from: depId, to: task.id });
    }
  }

  // 3. トポロジカルソート
  const sorted = this.topologicalSort(nodes, edges);

  // 4. 循環依存検出
  if (this.hasCyclicDependency(sorted)) {
    throw new Error('Circular dependency detected');
  }

  // 5. レベル算出(並行実行グループ)
  const levels = this.computeLevels(sorted, edges);

  return { nodes, edges, levels };
}

レベル順実行

async executeLevels(dag: DAG, concurrency: number): Promise<Result[]> {
  const results: Result[] = [];

  for (const level of dag.levels) {
    console.log(`Level ${level.index}: ${level.tasks.length} tasks`);

    // 同一レベル内は並行実行
    const chunks = this.chunkArray(level.tasks, concurrency);

    for (const chunk of chunks) {
      const chunkResults = await Promise.all(
        chunk.map(task => this.executeTask(task))
      );
      results.push(...chunkResults);
    }
  }

  return results;
}

DAG例

Issue #270の分解:

task-1: Firebase Auth修正
  dependencies: []
  priority: 1

task-2: E2Eテスト追加
  dependencies: [task-1]
  priority: 2

task-3: ドキュメント更新
  dependencies: [task-1, task-2]
  priority: 3

DAG構造:

Level 1:  [task-1]           ← 並行度1
Level 2:  [task-2]           ← task-1完了後
Level 3:  [task-3]           ← task-1,2完了後

task-1 → task-2 → task-3

Git Worktree分離

Worktree戦略

各ワーカーは独自の Git worktree を使用して完全な分離を実現。

# Worktree自動作成
async function setupWorktree(task: Task): Promise<string> {
  const worktreePath = `.worktrees/${task.id}`;
  const branchName = `${task.type}/${task.metadata.issueNumber}-${task.id}`;

  // Worktree作成
  await exec(`git worktree add ${worktreePath} -b ${branchName}`);

  // Worktree固有設定
  await exec(`cd ${worktreePath} && git config user.name "${worker.name}"`);

  return worktreePath;
}

ディレクトリ構造

Autonomous-Operations/
├── .git/                    # Main Git directory
├── .worktrees/              # Worktree root
│   ├── task-001/            # Worker 1's worktree
│   │   └── [full repo]
│   ├── task-002/            # Worker 2's worktree
│   │   └── [full repo]
│   └── task-003/            # Worker 3's worktree
│       └── [full repo]
├── src/                     # Main working directory
└── [other files]

ブランチ命名規則

<type>/<issue-number>-<task-id>-<description>

例:
- fix/456-task-001-auth-bug
- feat/789-task-002-add-oauth
- refactor/101-task-003-cleanup-utils

type の種類:

  • fix - バグ修正
  • feat - 新機能
  • refactor - リファクタリング
  • test - テスト追加
  • docs - ドキュメント
  • chore - その他

バッティング回避メカニズム

1. ファイルレベルの排他制御

const conflictDetector = new ConflictDetector();

// タスク割り当て前にチェック
const hasConflict = await conflictDetector.check(task, activeWorkers);

if (hasConflict) {
  // タスクを待機キューへ
  await taskQueue.defer(task);
} else {
  // 安全に割り当て
  await assignTask(task, worker);
}

衝突検出ロジック:

function detectFileConflicts(task: Task, activeTasks: Task[]): boolean {
  const taskFiles = new Set(task.metadata.files);

  for (const activeTask of activeTasks) {
    const activeFiles = new Set(activeTask.metadata.files);
    const overlap = intersection(taskFiles, activeFiles);

    if (overlap.size > 0) {
      return true; // 衝突検出
    }
  }

  return false;
}

2. Lock File管理

.task-locks/構造:

.task-locks/
├── task-001.lock          # Task-specific lock
├── task-002.lock
├── shared/
│   ├── package.json.lock  # Shared file locks
│   └── tsconfig.json.lock
└── cleanup.sh             # Expired lock cleanup script

Lock File形式:

// .task-locks/task-123.lock
{
  "taskId": "task-123",
  "workerId": "worker-alice",
  "workerType": "human",
  "claimedAt": "2025-10-10T03:00:00Z",
  "lockedFiles": [
    "src/auth/login.ts",
    "tests/auth/login.test.ts"
  ],
  "branchName": "fix/456-task-001-auth-bug",
  "expiresAt": "2025-10-10T04:00:00Z"
}

3. 共有リソースの保護

Critical Files(排他ロック必須):

  • package.json
  • package-lock.json
  • tsconfig.json
  • .github/workflows/*.yml

戦略:

  • 共有ファイルを変更するタスクは1つずつ実行
  • 他のタスクは解放されるまで待機

Task Claim Protocol

タスク取得フロー

1. Worker requests available tasks
   ↓
2. Orchestrator checks file conflicts
   ↓
3. If no conflicts: Create lock file
   ↓
4. Assign task to worker
   ↓
5. Worker claims task (status = 'claimed')
   ↓
6. Worker starts work (status = 'in_progress')
   ↓
7. Worker completes/fails (status = 'completed'/'failed')
   ↓
8. Release lock file

実装

class TaskClaimProtocol {
  async claimTask(workerId: WorkerId): Promise<Task | null> {
    // 1. 利用可能タスク取得
    const availableTasks = await this.orchestrator.getAvailableTasks(workerId);

    if (availableTasks.length === 0) {
      return null;
    }

    const task = availableTasks[0];

    // 2. ファイル衝突チェック
    const hasConflict = await this.detectConflicts(task);
    if (hasConflict) {
      return null;
    }

    // 3. ロックファイル作成
    await this.lockManager.acquireLock(task, workerId);

    // 4. タスク割り当て
    task.assignedTo = workerId;
    task.status = 'claimed';
    await this.orchestrator.updateTask(task);

    return task;
  }

  async releaseTask(taskId: string): Promise<void> {
    // ロック解放
    await this.lockManager.releaseLock(taskId);

    // タスク状態更新
    const task = await this.orchestrator.getTask(taskId);
    task.status = 'completed';
    await this.orchestrator.updateTask(task);
  }
}

進捗モニタリング

リアルタイム進捗表示

🚀 Claude Code Agent並行実行システム起動
📍 セッションID: session-1759552488828
🖥️  デバイス: MacBook Pro 16-inch

✅ Issue #270 登録完了 (Agent: CodeGenAgent, Priority: 1)
✅ Issue #240 登録完了 (Agent: CodeGenAgent, Priority: 1)

🎯 並行実行開始...
✅ 依存関係チェック完了(循環依存なし)

📊 進捗: 完了 0/2 | 実行中 2 | 待機中 0 | 失敗 0

[12:34:56] ⏳ [issue-270] 実行中... (CodeGenAgent)
[12:34:58] ⏳ [issue-240] 実行中... (CodeGenAgent)
[12:35:20] ✅ [issue-240] 完了 (22秒)
[12:35:35] ✅ [issue-270] 完了 (39秒)

📊 進捗: 完了 2/2 | 実行中 0 | 待機中 0 | 失敗 0

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 並行実行最終レポート
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🆔 セッションID: session-1759552488828
🖥️  デバイス: MacBook Pro 16-inch
⏱️  総実行時間: 39秒
📊 タスク統計:
  - 総タスク数: 2
  - 完了: 2 ✅
  - 失敗: 0 ❌
  - 成功率: 100.0%

ProgressMonitor実装

class ProgressMonitor {
  async getWorkerProgress(workerId: WorkerId): Promise<Progress> {
    const task = await this.getCurrentTask(workerId);

    return {
      taskId: task.id,
      currentStep: task.currentStep,
      stepsCompleted: task.stepsCompleted,
      totalSteps: task.totalSteps,
      percentComplete: (task.stepsCompleted / task.totalSteps) * 100,
      estimatedTimeRemaining: this.estimateTimeRemaining(task),
      lastUpdated: new Date()
    };
  }

  async getAllProgress(): Promise<Map<WorkerId, Progress>> {
    const workers = await this.registry.getActiveWorkers();
    const progress = new Map();

    for (const worker of workers) {
      progress.set(worker.id, await this.getWorkerProgress(worker.id));
    }

    return progress;
  }
}

実行モード

モード1: 疑似実行(デフォルト)

npm run agents:parallel:exec -- --issues=270,240 --concurrency=2

特徴:

  • Task tool API未使用
  • 実行ログのみ生成
  • デバッグ・テスト用

モード2: Task tool統合

USE_TASK_TOOL=true npm run agents:parallel:exec -- --issues=270

特徴:

  • Claude Code Task tool API使用
  • 実際のAgent実行
  • 本番運用モード

モード3: Worktree分離

USE_WORKTREE=true npm run agents:parallel:exec -- --issues=276

特徴:

  • Issue単位でWorktree自動作成
  • ブランチ完全分離
  • バッティング完全回避

ワークフロー例

シナリオ: 3人のワーカーが並列作業

ワーカー:

  • Alice (Human Developer)
  • Bob (AI Agent - CodeGen)
  • Charlie (AI Agent - Review)

タスク:

  • Task 1: Fix auth bug (files: src/auth/login.ts)
  • Task 2: Add OAuth (files: src/auth/oauth.ts)
  • Task 3: Update docs (files: docs/AUTH.md)

フロー:

T=0:
Alice:   claim-task → Task 1 assigned → Setup worktree → Lock files
Bob:     claim-task → Task 2 assigned → Setup worktree → Lock files
Charlie: claim-task → Task 3 assigned → Setup worktree → Lock files

T=5min:
Alice:   [Working] fix/456-task-001 (Progress: 40%)
Bob:     [Working] feat/789-task-002 (Progress: 60%)
Charlie: [Working] docs/101-task-003 (Progress: 80%)

T=10min:
Alice:   [Working] fix/456-task-001 (Progress: 70%)
Bob:     [Completed] feat/789-task-002 → Create PR → Auto-merge
Charlie: [Completed] docs/101-task-003 → Create PR → Auto-merge

T=15min:
Alice:   [Completed] fix/456-task-001 → Rebase main → Create PR
Bob:     [Idle] Ready for next task
Charlie: [Idle] Ready for next task

T=20min:
Alice:   [PR Merged] → Cleanup worktree → Release lock
Bob:     claim-task → Task 4 assigned
Charlie: claim-task → Task 5 assigned

マージ調整

マージ戦略

  1. 順次マージ: タスク完了順に main へマージ
  2. Rebase 優先: マージ前に main を rebase
  3. Conflict Resolution: 自動検出 → 人間介入
  4. Post-Merge Cleanup: worktree 削除、lock 解除

自動化フロー

async function completeTask(task: Task): Promise<void> {
  // 1. Fetch latest main
  await exec('git fetch origin main');

  // 2. Rebase on main
  await exec('git rebase origin/main');

  // 3. Run tests
  await exec('npm test');

  // 4. Create PR
  const pr = await createPullRequest(task);

  // 5. Auto-merge if checks pass
  if (await allChecksPass(pr)) {
    await mergePR(pr);
  }

  // 6. Cleanup
  await cleanupWorktree(task);
  await releaseLock(task);
}

パフォーマンス最適化

並行度の決定

function calculateOptimalConcurrency(tasks: Task[]): number {
  // CPUコア数
  const cpuCores = os.cpus().length;

  // 依存関係グラフの最大幅
  const maxWidth = this.calculateGraphWidth(tasks);

  // 最適並行度 = min(CPUコア数, グラフ最大幅)
  return Math.min(cpuCores, maxWidth, 10); // 上限10
}

キャッシュ戦略

class TaskCache {
  private cache = new Map<string, Task>();

  async getTask(taskId: string): Promise<Task> {
    if (this.cache.has(taskId)) {
      return this.cache.get(taskId)!;
    }

    const task = await this.fetchFromDB(taskId);
    this.cache.set(taskId, task);
    return task;
  }

  invalidate(taskId: string): void {
    this.cache.delete(taskId);
  }
}

トラブルシューティング

Issue 1: Worktree競合

症状:

fatal: 'worktrees/issue-270' already exists

解決策:

# 既存worktree確認
git worktree list

# 不要worktree削除
git worktree remove ~/Dev/worktrees/autonomous-operations/issue-270

# 自動クリーンアップ
git worktree prune

Issue 2: 依存関係循環検出

症状:

Error: Circular dependency detected: 300 → 270 → 300

解決策:

# Issue本文から依存記述削除
gh issue edit 300 --body "依存: #270のみ"

# または循環依存無視(非推奨)
npm run agents:parallel:exec -- --issues=300 --ignore-deps

関連ドキュメント


次のステップ


最終更新: 2025-10-10 バージョン: 2.0.0 管理者: AI Operations Lead