Beispiel #1
0
// Sample collects process statistcs and emits them.
func (ps *ProcessStatCollector) Sample() error {
	// Start a race between the timeout (if applicable) and the message
	// collection.

	done := make(chan error, 1)
	go func() {
		done <- ps.collectSample()
	}()

	var timerDone <-chan time.Time
	if ps.msgTimeout > 0*time.Second {
		timerDone = time.After(ps.msgTimeout)
	}

	select {
	case err := <-done:
		return err
	case <-timerDone:
		log.Warnln("Sample collection exceeded timeout")
		return fmt.Errorf("Sample collection exceeded timeout")
	}
}
Beispiel #2
0
func main() {
	if *debugMode {
		log.SetLevel(log.DebugLevel)
	} else if *noWarn {
		log.SetLevel(log.ErrorLevel)
	}

	// Create channel for ProcessStats to trigger a sample
	psChan := make(chan agents.ProcessStatCommand)
	// Incoming remote command channel (new with each reconnect)
	rcChan := make(chan chan agents.RemoteControlCommand)

	args := flag.Args()
	var cmdArgs []string
	var cmd string
	if len(args) > 0 {
		cmd = args[0]
	} else {
		log.Fatal("Did you forget a command to run?")
		return
	}

	log.Debugf("cmd: %s cmdArgs: %q\n", cmd, cmdArgs)

	done := make(chan error)

	// Initialize job
	job, err := agents.NewControlledProcess(cmd, args, done, *stdoutByteLimit)
	if err != nil {
		log.Fatalf("Failed to create a NewControlledProcess: %s\n", err)
		return
	}

	log.Debugf("%#v\n", job)

	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)

	timer, err := agents.NewTimer(*wallclockTimeout)
	if err != nil {
		log.Warnln("Error returned creating timeout agent", err)
	}
	log.Debugf("Starting timer with timeout of: %v\n", *wallclockTimeout)
	timer.Start()

	sess := session{
		job:          job,
		exchange:     *exchange,
		rcRoutingKey: *rmtKey,
		psChan:       psChan,
		rcChan:       rcChan,
		amqpConfig: amqp.Config{
			Properties: amqp.Table{
				"product": "proc_box",
				"version": "master",
			},
		},
		multiRmtKey: *multiRmtKey,
	}
	go redial(sess)

	go monitor(signals, rcChan, job, psChan, timer, done)

	err = <-done

	elapsedTime, _ := timer.ElapsedTime()
	// Print to standard out
	fmt.Printf("Task elapsed time: %.2f seconds.\n", elapsedTime.Seconds())

	if err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// Non-zero exit code
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				exitStatus := status.ExitStatus()
				log.Debugf("Exit Status: %d\n", exitStatus)
				os.Exit(exitStatus)
			}
		} else {
			log.Debugf("cmd.Wait: %v\n", err)
		}
	} else {
		os.Exit(0)
	}
}
Beispiel #3
0
func redial(sess session) {
	var err error
	var stats agents.ProcessStats
	var rc *agents.RemoteControl

	// Initialize mini-router for incoming stats agent requests
	go func() {
		for s := range sess.psChan {
			if stats == nil {
				log.Warnln("No stats agents available (yet), dropping request")
			} else if s.TimeUpdate {
				stats.NewTicker(s.NewTime)
			} else {
				stats.Sample()
			}
		}
	}()

	rcKeys := []string{*rmtKey}
	if sess.multiRmtKey {
		rcKeys = deleteEmpty(strings.Split(*rmtKey, ","))
	}
	for {
		sess.amqpConn, err = amqp.DialConfig(*uri, sess.amqpConfig)

		if err != nil {
			log.Warnf("Failed to connect to AMQP: %q", err)
			// Rate limit reconnection attempts
			time.Sleep(5 * time.Second)
		} else {
			rc, err = agents.NewRemoteControl(sess.amqpConn, rcKeys, *exchange)
			if err != nil {
				log.Warnf("Failed creating NewRemoteControl: %s", err)
			} else {
				sess.rcChan <- rc.Commands
			}

			if stats == nil {
				// initial setup
				stats, err = agents.NewProcessStats(
					sess.amqpConn,
					*procStatsKey,
					*exchange,
					&sess.job,
					*statsInterval,
					*msgTimeout,
					*userJSON,
				)
				if err != nil {
					log.Warnf("Failed creating NewProcessStats: %s", err)
				}
			} else {
				err = stats.ReinitializeConnection(sess.amqpConn)
				if err != nil {
					log.Warnf("Failed to reinitialize process stats: %s", err)
				}
			}
			closings := sess.amqpConn.NotifyClose(make(chan *amqp.Error))

			// Wait for close notification and loop back around to reconnect
			_ = <-closings
			log.Debugln("Saw a notification for closed connection, looping")
		}

	}
}