github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/taskrunner/task_runner.go (about)

     1  package taskrunner
     2  
     3  import (
     4  	"path/filepath"
     5  	"runtime"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/evergreen-ci/evergreen"
    10  	"github.com/evergreen-ci/evergreen/model/host"
    11  	"github.com/mongodb/grip"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  // TODO: take out task queue finder and host finder once transition is complete
    16  type TaskRunner struct {
    17  	*evergreen.Settings
    18  	HostGateway
    19  }
    20  
    21  func NewTaskRunner(settings *evergreen.Settings) *TaskRunner {
    22  	// get mci home, and set the source and destination for the agent
    23  	// executables
    24  	evgHome := evergreen.FindEvergreenHome()
    25  
    26  	return &TaskRunner{
    27  		settings,
    28  		&AgentHostGateway{
    29  			ExecutablesDir: filepath.Join(evgHome, settings.AgentExecutablesDir),
    30  		},
    31  	}
    32  }
    33  
    34  // agentStartData is the information needed to start an agent on a host
    35  type agentStartData struct {
    36  	Host     host.Host
    37  	Settings *evergreen.Settings
    38  }
    39  
    40  func (tr *TaskRunner) Run() error {
    41  	// Find all hosts that are running and have a LCT (last communication time)
    42  	// of 0 or ones that haven't been communicated in MaxLCT time.
    43  	// These are the hosts that need to have agents dispatched
    44  	freeHosts, err := host.Find(host.ByRunningWithTimedOutLCT(time.Now()))
    45  	if err != nil {
    46  		return err
    47  	}
    48  
    49  	grip.Infof("Found %d hosts that need agents dispatched", len(freeHosts))
    50  
    51  	freeHostChan := make(chan agentStartData, len(freeHosts))
    52  
    53  	// put all of the information needed about the host in a channel
    54  	for _, h := range freeHosts {
    55  		freeHostChan <- agentStartData{
    56  			Host:     h,
    57  			Settings: tr.Settings,
    58  		}
    59  	}
    60  	// close the free hosts channel
    61  	close(freeHostChan)
    62  	wg := sync.WaitGroup{}
    63  	workers := runtime.NumCPU()
    64  	wg.Add(workers)
    65  
    66  	catcher := grip.NewCatcher()
    67  	// for each worker create a new goroutine
    68  	for i := 0; i < workers; i++ {
    69  		go func() {
    70  			defer wg.Done()
    71  			for input := range freeHostChan {
    72  				catcher.Add(errors.Wrapf(tr.StartAgentOnHost(input.Settings, input.Host),
    73  					"problem starting agent on host %s", input.Host.Id))
    74  			}
    75  		}()
    76  	}
    77  	wg.Wait()
    78  	return catcher.Resolve()
    79  }