func main() { mlvl := metafora.LogLevelInfo hostname, _ := os.Hostname() peers := flag.String("etcd", "http://127.0.0.1:2379", "comma delimited etcd peer list") namespace := flag.String("namespace", "koalemos", "metafora namespace") name := flag.String("name", hostname, "node name or empty for automatic") loglvl := flag.String("log", mlvl.String(), "set log level: [debug], info, warn, error") flag.Parse() hosts := strings.Split(*peers, ",") etcdc := etcd.NewClient(hosts) switch strings.ToLower(*loglvl) { case "debug": mlvl = metafora.LogLevelDebug case "info": mlvl = metafora.LogLevelInfo case "warn": mlvl = metafora.LogLevelWarn case "error": mlvl = metafora.LogLevelError default: metafora.Warnf("Invalid log level %q - using %s", *loglvl, mlvl) } metafora.SetLogLevel(mlvl) conf := m_etcd.NewConfig(*name, *namespace, hosts) // Replace NewTask func with one that returns a *koalemos.Task conf.NewTaskFunc = func(id, value string) metafora.Task { t := koalemos.NewTask(id) if value == "" { return t } if err := json.Unmarshal([]byte(value), t); err != nil { metafora.Errorf("Unable to unmarshal task %s: %v", t.ID(), err) return nil } return t } hfunc := makeHandlerFunc(etcdc) ec, err := m_etcd.NewEtcdCoordinator(conf) if err != nil { metafora.Errorf("Error creating etcd coordinator: %v", err) } bal := m_etcd.NewFairBalancer(conf) c, err := metafora.NewConsumer(ec, hfunc, bal) if err != nil { metafora.Errorf("Error creating consumer: %v", err) os.Exit(2) } metafora.Infof( "Starting koalsmosd with etcd=%s; namespace=%s; name=%s; loglvl=%s", *peers, conf.Namespace, conf.Name, mlvl) consumerRunning := make(chan struct{}) go func() { defer close(consumerRunning) c.Run() }() sigC := make(chan os.Signal, 1) signal.Notify(sigC, os.Interrupt, os.Kill, syscall.SIGTERM) select { case s := <-sigC: metafora.Infof("Received signal %s, shutting down", s) case <-consumerRunning: metafora.Warn("Consumer exited. Shutting down.") } c.Shutdown() metafora.Info("Shutdown") }
// Start the grid. Actors that were stopped from a previous exit // of the grid but returned a "done" status of false will start // to be scheduled. New actors can be scheduled with StartActor. func (g *grid) Start() (<-chan bool, error) { g.mu.Lock() defer g.mu.Unlock() // Start only once. if g.started { return g.exit, nil } // Use the hostname as the node identifier. hostname, err := os.Hostname() if err != nil { return nil, err } nodeid := fmt.Sprintf("%s-%s", hostname, g.name) // Define the metafora new task function and config. conf := m_etcd.NewConfig(nodeid, g.name, g.etcdservers) conf.NewTaskFunc = func(id, value string) metafora.Task { def := NewActorDef(id) err := json.Unmarshal([]byte(value), def) if err != nil { log.Printf("error: failed to schedule actor: %v, error: %v", id, err) return nil } a, err := g.maker.MakeActor(def) if err != nil { log.Printf("error: failed to schedule actor: %v, error: %v", id, err) return nil } return newHandler(g.fork(), a) } // Create the metafora etcd coordinator. ec, err := m_etcd.NewEtcdCoordinator(conf) if err != nil { return nil, err } // Create the metafora consumer. c, err := metafora.NewConsumer(ec, handler(etcd.NewClient(g.etcdservers)), m_etcd.NewFairBalancer(conf)) if err != nil { return nil, err } g.metaconsumer = c g.metaclient = m_etcd.NewClient(g.name, g.etcdservers) g.stopped = false g.started = true // Close the exit channel when metafora thinks // an exit is needed. go func() { defer close(g.exit) g.metaconsumer.Run() }() for i := 0; i < 2*runtime.NumCPU(); i++ { natsconn, err := g.newNatsConn() if err != nil { return nil, err } g.natsconnpool[i] = natsconn if i == 0 { g.natsconn = g.natsconnpool[0] } } return g.exit, nil }