processComponentsInParallel processes all components using parallel workers
(ctx context.Context, components []app.SnapshotComponent, data *validateVSAData)
| 488 | |
| 489 | // processComponentsInParallel processes all components using parallel workers |
| 490 | func processComponentsInParallel(ctx context.Context, components []app.SnapshotComponent, data *validateVSAData) ([]vsa.ComponentResult, error) { |
| 491 | numComponents := len(components) |
| 492 | numWorkers := data.workers |
| 493 | |
| 494 | printVSAInfo(os.Stdout, fmt.Sprintf("Found %d components in snapshot", numComponents)) |
| 495 | printVSAInfo(os.Stdout, fmt.Sprintf("=== Processing Components in Parallel (%d workers) ===", numWorkers)) |
| 496 | |
| 497 | // Add timeout for parallel processing to prevent hanging |
| 498 | ctx, cancel := context.WithTimeout(ctx, DefaultTimeoutDuration) |
| 499 | defer cancel() |
| 500 | |
| 501 | // Set up parallel processing infrastructure |
| 502 | jobs := make(chan app.SnapshotComponent, numComponents) |
| 503 | results := make(chan vsa.ComponentResult, numComponents) |
| 504 | |
| 505 | // Use WaitGroup to track worker completion |
| 506 | var wg sync.WaitGroup |
| 507 | |
| 508 | // Start worker goroutines |
| 509 | for i := 0; i < numWorkers; i++ { |
| 510 | wg.Add(1) |
| 511 | go func() { |
| 512 | defer wg.Done() |
| 513 | worker(jobs, results, ctx, data) |
| 514 | }() |
| 515 | } |
| 516 | |
| 517 | // Close results channel after all workers finish |
| 518 | go func() { |
| 519 | wg.Wait() |
| 520 | close(results) |
| 521 | }() |
| 522 | |
| 523 | // Send all components to workers |
| 524 | for _, component := range components { |
| 525 | select { |
| 526 | case jobs <- component: |
| 527 | // Component sent successfully |
| 528 | case <-ctx.Done(): |
| 529 | close(jobs) |
| 530 | // Don't wait for workers - context cancellation will signal them to stop |
| 531 | // and the results channel will be closed by the goroutine after workers finish |
| 532 | return nil, fmt.Errorf("parallel processing timeout after %v: %w", DefaultTimeoutDuration, ctx.Err()) |
| 533 | } |
| 534 | } |
| 535 | close(jobs) |
| 536 | |
| 537 | // Collect results with timeout handling |
| 538 | var allResults []vsa.ComponentResult |
| 539 | for i := 0; i < numComponents; i++ { |
| 540 | select { |
| 541 | case result, ok := <-results: |
| 542 | if !ok { |
| 543 | // Channel closed, but we haven't received all results |
| 544 | // This shouldn't happen normally, but handle gracefully |
| 545 | return allResults, fmt.Errorf("results channel closed prematurely (received %d/%d results)", len(allResults), numComponents) |
| 546 | } |
| 547 | allResults = append(allResults, result) |
no test coverage detected