github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/internal/task/executor.go (about)

     1  package task
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"runtime/debug"
     7  	"sync"
     8  
     9  	"github.com/hashicorp/go-multierror"
    10  
    11  	"github.com/anchore/syft/internal/sbomsync"
    12  	"github.com/anchore/syft/syft/event/monitor"
    13  	"github.com/anchore/syft/syft/file"
    14  )
    15  
    16  type Executor struct {
    17  	numWorkers int
    18  	tasks      chan Task
    19  }
    20  
    21  func NewTaskExecutor(tasks []Task, numWorkers int) *Executor {
    22  	p := &Executor{
    23  		numWorkers: numWorkers,
    24  		tasks:      make(chan Task, len(tasks)),
    25  	}
    26  
    27  	for i := range tasks {
    28  		p.tasks <- tasks[i]
    29  	}
    30  	close(p.tasks)
    31  
    32  	return p
    33  }
    34  
    35  func (p *Executor) Execute(ctx context.Context, resolver file.Resolver, s sbomsync.Builder, prog *monitor.CatalogerTaskProgress) error {
    36  	var errs error
    37  	wg := &sync.WaitGroup{}
    38  	for i := 0; i < p.numWorkers; i++ {
    39  		wg.Add(1)
    40  		go func() {
    41  			defer wg.Done()
    42  
    43  			for {
    44  				tsk, ok := <-p.tasks
    45  				if !ok {
    46  					return
    47  				}
    48  
    49  				if err := runTaskSafely(ctx, tsk, resolver, s); err != nil {
    50  					errs = multierror.Append(errs, fmt.Errorf("failed to run task: %w", err))
    51  					prog.SetError(err)
    52  				}
    53  				prog.Increment()
    54  			}
    55  		}()
    56  	}
    57  
    58  	wg.Wait()
    59  
    60  	return errs
    61  }
    62  
    63  func runTaskSafely(ctx context.Context, t Task, resolver file.Resolver, s sbomsync.Builder) (err error) {
    64  	// handle individual cataloger panics
    65  	defer func() {
    66  		if e := recover(); e != nil {
    67  			err = fmt.Errorf("%v at:\n%s", e, string(debug.Stack()))
    68  		}
    69  	}()
    70  
    71  	return t.Execute(ctx, resolver, s)
    72  }