func (qmd *Qmd) ListenQueue() { qmd.WaitListenQueue.Add(1) defer qmd.WaitListenQueue.Done() lg.Debug("Queue:\tListening") for { select { // Wait for some worker to become available. case worker := <-qmd.Workers: // Dequeue job or try again. job, err := qmd.Dequeue() if err != nil { qmd.Workers <- worker break } lg.Debugf("Queue:\tDequeued job %v", job.ID) // Send the job to the worker. worker <- job case <-qmd.ClosingListenQueue: lg.Debug("Queue:\tStopped listening") return } } }
func (cmd *Cmd) Kill() error { switch cmd.State { case Running: cmd.State = Terminated lg.Debugf("Cmd:\tKilling %v\n", cmd.JobID) pgid, err := syscall.Getpgid(cmd.Cmd.Process.Pid) if err != nil { // Fall-back on error. Kill the main process only. cmd.Cmd.Process.Kill() break } // Kill the whole process group. syscall.Kill(-pgid, 15) case Finished: lg.Debug("Cmd:\tKilling pgroup %v\n", cmd.JobID) pgid, err := syscall.Getpgid(cmd.Cmd.Process.Pid) if err != nil { break } // Make sure to kill the whole process group, // so there are no subprocesses left. syscall.Kill(-pgid, 15) case Initialized: // This one is tricky, as the cmd's Start() might have // been called and is already in progress, but the cmd's // state is not Running yet. usCallingStartOnce := false cmd.StartOnce.Do(func() { cmd.WaitOnce.Do(func() { cmd.State = Invalidated cmd.StatusCode = -2 cmd.Err = errors.New("invalidated") lg.Debugf("Cmd: Invalidating %v\n", cmd.JobID) close(cmd.Finished) }) close(cmd.Started) usCallingStartOnce = true }) if !usCallingStartOnce { // It was cmd.Start() that called StartOnce.Do(), not us, // thus we need to wait for Started and try to Kill again: <-cmd.Started cmd.Kill() } } return cmd.Err }
func (qmd *Qmd) Close() { lg.Debug("Closing") qmd.Closing = true close(qmd.ClosingListenQueue) qmd.WaitListenQueue.Wait() close(qmd.ClosingWorkers) qmd.WaitWorkers.Wait() qmd.DB.Close() qmd.Queue.Close() }
// Update walks ScriptDir directory for shell scripts and updates the files cache. func (s *Scripts) Update(dir string) error { info, err := os.Stat(dir) if err != nil { return errors.New("script_dir=\"" + dir + "\": no such directory") } if !info.IsDir() { return errors.New("script_dir=\"" + dir + "\": not a directory") } files := map[string]string{} if err := filepath.Walk(dir, func(file string, info os.FileInfo, err error) error { if !info.IsDir() { if path.Ext(file) == ".sh" { rel, err := filepath.Rel(dir, file) if err != nil { return err } files[rel] = file } } return nil }); err != nil { return err } if len(files) == 0 { return errors.New("script_dir=\"" + dir + "\" is empty") } s.Lock() defer s.Unlock() if !reflect.DeepEqual(s.files, files) { lg.Debug("Scripts: Loading new files from script_dir:") for rel, _ := range files { lg.Debugf("Scripts: - %v", rel) } } s.files = files return nil }