func (s *Sentinel) Start() { endCh := make(chan struct{}) endApiCh := make(chan error) router := s.NewRouter() go func() { endApiCh <- http.ListenAndServe(fmt.Sprintf("%s:%s", s.listenAddress, s.port), router) }() ctx, cancel := context.WithCancel(context.Background()) timerCh := time.NewTimer(0).C for true { select { case <-s.stop: log.Debugf("stopping stolon sentinel") cancel() s.end <- true return case <-timerCh: go func() { s.clusterSentinelCheck(ctx) endCh <- struct{}{} }() case <-endCh: timerCh = time.NewTimer(s.clusterConfig.SleepInterval).C case err := <-endApiCh: if err != nil { log.Fatal("ListenAndServe: ", err) } close(s.stop) } } }
func (p *PostgresKeeper) Start() { endSMCh := make(chan struct{}) endPgStatecheckerCh := make(chan struct{}) endApiCh := make(chan error) err := p.loadCVVersion() if err != nil { p.end <- err return } p.pgm.Stop(true) http.HandleFunc("/info", p.infoHandler) http.HandleFunc("/pgstate", p.pgStateHandler) go func() { endApiCh <- http.ListenAndServe(fmt.Sprintf("%s:%s", p.listenAddress, p.port), nil) }() ctx, cancel := context.WithCancel(context.Background()) smTimerCh := time.NewTimer(0).C updatePGStateTimerCh := time.NewTimer(0).C for true { select { case <-p.stop: log.Debugf("stopping postgres keeper") cancel() p.pgm.Stop(true) p.end <- nil return case <-smTimerCh: go func() { p.postgresKeeperSM(ctx) endSMCh <- struct{}{} }() case <-endSMCh: smTimerCh = time.NewTimer(p.clusterConfig.SleepInterval).C case <-updatePGStateTimerCh: go func() { p.updatePGState(ctx) endPgStatecheckerCh <- struct{}{} }() case <-endPgStatecheckerCh: updatePGStateTimerCh = time.NewTimer(p.clusterConfig.SleepInterval).C case err := <-endApiCh: if err != nil { log.Fatal("ListenAndServe: ", err) } close(p.stop) } } }
func (s *Sentinel) Start() { endCh := make(chan struct{}) ctx, cancel := context.WithCancel(context.Background()) timerCh := time.NewTimer(0).C for true { select { case <-s.stop: log.Debugf("stopping postgres keeper") cancel() s.end <- true return case <-timerCh: go func() { s.clusterSentinelSM(ctx) endCh <- struct{}{} }() case <-endCh: timerCh = time.NewTimer(s.clusterConfig.SleepInterval).C } } }
func (p *PostgresKeeper) Start() { endSMCh := make(chan struct{}) endPgStatecheckerCh := make(chan struct{}) endApiCh := make(chan error) var err error var cd *cluster.ClusterData // TODO(sgotti) make the postgres manager stateless and instantiate a // new one at every check loop, this will avoid the need to loop here // to get the clusterconfig for { cd, _, err = p.e.GetClusterData() if err == nil { break } log.Errorf("error retrieving cluster data: %v", err) time.Sleep(cluster.DefaultSleepInterval) } var cv *cluster.ClusterView if cd == nil { cv = cluster.NewClusterView() } else { cv = cd.ClusterView } log.Debugf(spew.Sprintf("clusterView: %#v", cv)) p.clusterConfig = cv.Config.ToConfig() log.Debugf(spew.Sprintf("clusterConfig: %#v", p.clusterConfig)) if err := p.loadCVVersion(); err != nil { p.end <- fmt.Errorf("failed to load cluster version file: %v", err) return } // TODO(sgotti) reconfigure the various configurations options (PGRepl* // and RequestTimeout) after a changed cluster config followersIDs := cv.GetFollowersIDs(p.id) pgParameters := p.createPGParameters(followersIDs) pgm := postgresql.NewManager(p.id, cfg.pgBinPath, cfg.dataDir, cfg.pgConfDir, pgParameters, p.getOurConnString(), p.getOurReplConnString(), p.clusterConfig.PGReplUser, p.clusterConfig.PGReplPassword, p.clusterConfig.RequestTimeout) p.pgm = pgm p.pgm.Stop(true) http.HandleFunc("/info", p.infoHandler) http.HandleFunc("/pgstate", p.pgStateHandler) go func() { endApiCh <- http.ListenAndServe(fmt.Sprintf("%s:%s", p.listenAddress, p.port), nil) }() ctx, cancel := context.WithCancel(context.Background()) smTimerCh := time.NewTimer(0).C updatePGStateTimerCh := time.NewTimer(0).C for true { select { case <-p.stop: log.Debugf("stopping stolon keeper") cancel() p.pgm.Stop(true) p.end <- nil return case <-smTimerCh: go func() { p.postgresKeeperSM(ctx) endSMCh <- struct{}{} }() case <-endSMCh: smTimerCh = time.NewTimer(p.clusterConfig.SleepInterval).C case <-updatePGStateTimerCh: go func() { p.updatePGState(ctx) endPgStatecheckerCh <- struct{}{} }() case <-endPgStatecheckerCh: updatePGStateTimerCh = time.NewTimer(p.clusterConfig.SleepInterval).C case err := <-endApiCh: if err != nil { log.Fatal("ListenAndServe: ", err) } close(p.stop) } } }
func (c *simpleHTTPClient) Do(ctx context.Context, act httpAction) (*http.Response, []byte, error) { req := act.HTTPRequest(c.endpoint) if err := printcURL(req); err != nil { return nil, nil, err } var hctx context.Context var hcancel context.CancelFunc if c.headerTimeout > 0 { hctx, hcancel = context.WithTimeout(ctx, c.headerTimeout) } else { hctx, hcancel = context.WithCancel(ctx) } defer hcancel() reqcancel := requestCanceler(c.transport, req) rtchan := make(chan roundTripResponse, 1) go func() { resp, err := c.transport.RoundTrip(req) rtchan <- roundTripResponse{resp: resp, err: err} close(rtchan) }() var resp *http.Response var err error select { case rtresp := <-rtchan: resp, err = rtresp.resp, rtresp.err case <-hctx.Done(): // cancel and wait for request to actually exit before continuing reqcancel() rtresp := <-rtchan resp = rtresp.resp switch { case ctx.Err() != nil: err = ctx.Err() case hctx.Err() != nil: err = fmt.Errorf("client: endpoint %s exceeded header timeout", c.endpoint.String()) default: panic("failed to get error from context") } } // always check for resp nil-ness to deal with possible // race conditions between channels above defer func() { if resp != nil { resp.Body.Close() } }() if err != nil { return nil, nil, err } var body []byte done := make(chan struct{}) go func() { body, err = ioutil.ReadAll(resp.Body) done <- struct{}{} }() select { case <-ctx.Done(): resp.Body.Close() <-done return nil, nil, ctx.Err() case <-done: } return resp, body, err }