func markTerminated(conn *zk.Conn, hss *zzk.HostServiceState) { ssPath := zzk.ServiceStatePath(hss.ServiceId, hss.ServiceStateId) _, stats, err := conn.Get(ssPath) if err != nil { glog.V(0).Infof("Unable to get service state %s for delete because: %v", ssPath, err) return } err = conn.Delete(ssPath, stats.Version) if err != nil { glog.V(0).Infof("Unable to delete service state %s because: %v", ssPath, err) return } hssPath := zzk.HostServiceStatePath(hss.HostId, hss.ServiceStateId) _, stats, err = conn.Get(hssPath) if err != nil { glog.V(0).Infof("Unable to get host service state %s for delete becaus: %v", hssPath, err) return } err = conn.Delete(hssPath, stats.Version) if err != nil { glog.V(0).Infof("Unable to delete host service state %s", hssPath) } }
func (a *HostAgent) processServiceState(conn *zk.Conn, shutdown <-chan int, done chan<- stateResult, ssId string) { procFinished := make(chan int, 1) var attached bool for { var hss zzk.HostServiceState hssStats, zkEvent, err := zzk.LoadHostServiceStateW(conn, a.hostId, ssId, &hss) if err != nil { errS := fmt.Sprintf("Unable to load host service state %s: %v", ssId, err) glog.Error(errS) done <- stateResult{ssId, errors.New(errS)} return } if len(hss.ServiceStateId) == 0 || len(hss.ServiceId) == 0 { errS := fmt.Sprintf("Service for %s is invalid", zzk.HostServiceStatePath(a.hostId, ssId)) glog.Error(errS) done <- stateResult{ssId, errors.New(errS)} return } var ss dao.ServiceState ssStats, err := zzk.LoadServiceState(conn, hss.ServiceId, hss.ServiceStateId, &ss) if err != nil { errS := fmt.Sprintf("Host service state unable to load service state %s", ssId) glog.Error(errS) // This goroutine is watching a node for a service state that does not // exist or could not be loaded. We should *probably* delete this node. hssPath := zzk.HostServiceStatePath(a.hostId, ssId) err = conn.Delete(hssPath, hssStats.Version) if err != nil { glog.Warningf("Unable to delete host service state %s", hssPath) } done <- stateResult{ssId, errors.New(errS)} return } var service dao.Service _, err = zzk.LoadService(conn, ss.ServiceId, &service) if err != nil { errS := fmt.Sprintf("Host service state unable to load service %s", ss.ServiceId) glog.Errorf(errS) done <- stateResult{ssId, errors.New(errS)} return } glog.V(1).Infof("Processing %s, desired state: %d", service.Name, hss.DesiredState) switch { case hss.DesiredState == dao.SVC_STOP: // This node is marked for death glog.V(1).Infof("Service %s was marked for death, quitting", service.Name) if attached { err = a.terminateAttached(conn, procFinished, &ss) } else { err = a.terminateInstance(conn, &ss) } done <- stateResult{ssId, err} return case attached: // Something uninteresting happened. Why are we here? glog.V(1).Infof("Service %s is attached in a child goroutine", service.Name) case hss.DesiredState == dao.SVC_RUN && ss.Started.Year() <= 1 || ss.Terminated.Year() > 2: // Should run, and either not started or process died glog.V(1).Infof("Service %s does not appear to be running; starting", service.Name) attached, err = a.startService(conn, procFinished, ssStats, &service, &ss) case ss.Started.Year() > 1 && ss.Terminated.Year() <= 1: // Service superficially seems to be running. We need to attach glog.V(1).Infof("Service %s appears to be running; attaching", service.Name) attached, err = a.attachToService(conn, procFinished, &ss, &hss) default: glog.V(0).Infof("Unhandled service %s", service.Name) } if !attached || err != nil { errS := fmt.Sprintf("Service state %s unable to start or attach to process", ssId) glog.V(1).Info(errS) a.terminateInstance(conn, &ss) done <- stateResult{ssId, errors.New(errS)} return } glog.V(3).Infoln("Successfully processed state for %s", service.Name) select { case <-shutdown: glog.V(0).Info("Agent goroutine will stop watching ", ssId) err = a.terminateAttached(conn, procFinished, &ss) if err != nil { glog.Errorf("Error terminating %s: %v", service.Name, err) } done <- stateResult{ssId, err} return case <-procFinished: glog.V(1).Infof("Process finished %s", ssId) attached = false continue case evt := <-zkEvent: if evt.Type == zk.EventNodeDeleted { glog.V(0).Info("Host service state deleted: ", ssId) err = a.terminateAttached(conn, procFinished, &ss) if err != nil { glog.Errorf("Error terminating %s: %v", service.Name, err) } done <- stateResult{ssId, err} return } glog.V(1).Infof("Host service state %s received event %v", ssId, evt) continue } } }