func (p Purgatory) AddJob(j Job) { p.lock.Lock() defer p.lock.Unlock() pr := GetProject(j.Project) if w, ok := pr.GetWorker(j.Name); ok && j.Version <= w.Version { // we've already got the worker jobQueue.Push <- j jobClaims.setJobStatus(j.JobHeader, messages.JobQueued) log.Println("queueing", j) return } log.Printf("adding %v to purgatory", j) jobClaims.setJobStatus(j.JobHeader, messages.JobAwaitingWorker) // otherwise store it and wait for the job to arrive prjs, ok := p.workerlessJobs[j.Project] if !ok { prjs = make(map[string][]Job) p.workerlessJobs[j.Project] = prjs } prjs[j.Name] = append(prjs[j.Name], j) var wr = messages.WorkerRequest{} wr.Project = j.Project wr.Name = j.Name var line messages.Line if line, ok = getLine(j.Conn); !ok { log.Printf("unknown connection w/ %v", j) } line.Out <- wr.Message() }
/* pull jobs from the backlog and request their workers */ func workerRequestLoop() { for { j := (<-backLog.Pop).(Job) wr := messages.WorkerRequest{ Project: j.Project, Name: j.Name, } mline, ok := getLine(j.Conn) if !ok { log.Println("job with no connection") } mline.Out <- wr.Message() } }
// this function ensures that the job has the right worker before queuing it func prepareJobForQueue(j Job) { jobClaims.claimJob(j.JobHeader) ja := messages.JobAck{j.JobHeader} if line, ok := getLine(j.Conn); ok { line.Out <- ja.Message() } pr := GetProject(j.Project) // first, ensure that we've got the worker alreadyRequested := false waitforworker: for { w, ok := pr.GetWorker(j.Name) if ok && j.Version <= w.Version { // we've already got the right worker break } workerChan := make(chan Worker) workerSub := func(msg messages.Message, line messages.Line) (keepgoing bool) { if string(msg.Payload["type"]) != messages.WorkerType { return true } worker, err := messages.WorkerFromMessage(msg) if err != nil { return true } if worker.Project != j.Project || worker.Name != j.Name { return true } if worker.Version < j.Version { return true } // this is our worker w := Worker{worker, line.Conn} pr.AddWorker(w) workerChan <- w // stop this subscription return false } if !alreadyRequested { alreadyRequested = true log.Printf("requesting worker for %v", j) wr := messages.WorkerRequest{ Project: j.Project, Name: j.Name, Version: j.Version, } line, ok := getLine(j.Conn) if !ok { log.Printf("job came from lost source") } line.Out <- wr.Message() } go subscribe(workerSub) timeout := time.NewTimer(2e9) select { case w = <-workerChan: break waitforworker case <-timeout.C: /* this timeout is here because we might have received the worker between the first check and when the subscription went active */ } timeout.Stop() } log.Printf("enqueuing %v", j) jobQueue.Push <- j }