// Start the app on the configured host/port. // // Supports graceful shutdown on 'kill' and 'int' signals. func (app *App) Run() error { // toggle heartbeat on SIGUSR1 go func() { app.heartbeater.Start() heartbeatChan := make(chan os.Signal, 1) signal.Notify(heartbeatChan, syscall.SIGUSR1) for s := range heartbeatChan { log.Infof("Received signal: %v, toggling heartbeat", s) app.heartbeater.Toggle() } }() // listen for a shutdown signal go func() { exitChan := make(chan os.Signal, 1) signal.Notify(exitChan, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM) s := <-exitChan log.Infof("Got shutdown signal: %v", s) manners.Close() }() addr := fmt.Sprintf("%v:%v", app.Config.ListenIP, app.Config.ListenPort) return manners.ListenAndServe(addr, app.router) }
// Subscribe watches etcd changes and generates structured events telling vulcand to add or delete frontends, hosts etc. // It is a blocking function. func (n *ng) Subscribe(changes chan interface{}, cancelC chan bool) error { // This index helps us to get changes in sequence, as they were performed by clients. waitIndex := uint64(0) for { response, err := n.client.Watch(n.etcdKey, waitIndex, true, nil, cancelC) if err != nil { switch err { case etcd.ErrWatchStoppedByUser: log.Infof("Stop watching: graceful shutdown") return nil default: log.Errorf("unexpected error: %s, stop watching", err) return err } } waitIndex = response.Node.ModifiedIndex + 1 log.Infof("%s", responseToString(response)) change, err := n.parseChange(response) if err != nil { log.Warningf("Ignore '%s', error: %s", responseToString(response), err) continue } if change != nil { log.Infof("%v", change) select { case changes <- change: case <-cancelC: return nil } } } }
func (n *ng) buildDbCluster() error { dbEndpoints := n.path("cassandra", "hosts") var cassandraPool *cassandraPool err := n.getJSONVal(dbEndpoints, &cassandraPool) if err != nil { return err } log.Infof("===> Syncing up Migrations with the cluster") allErr, ok := migrate.UpSync("cassandra://"+cassandraPool.Nodes[0]+"/"+cassandraPool.Keyspace, "./migrations") if !ok { return allErr[0] } log.Infof("===> Migrations are in sync") log.Infof("===> Connecting to the database cluster") db := gocql.NewCluster(cassandraPool.Nodes...) db.Keyspace = cassandraPool.Keyspace db.NumConns = cassandraPool.NumConns db.DiscoverHosts = true db.Discovery = gocql.DiscoveryConfig{ DcFilter: "", RackFilter: "", Sleep: 30 * time.Second, } n.Database = db log.Infof("===> Connected to the database cluster") return nil }
// Stop halts sending heartbeats. func (h *Heartbeater) Stop() { log.Infof("Stopping heartbeat for app: %v", h.registration) close(h.quit) h.ticker.Stop() h.Running = false }
// Make a handler out of HandlerWithBodyFunc, just like regular MakeHandler function. func MakeHandlerWithBody(app *App, fn HandlerWithBodyFunc, spec Spec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if err := parseForm(r); err != nil { ReplyInternalError(w, fmt.Sprintf("Failed to parse request form: %v", err)) return } body, err := ioutil.ReadAll(r.Body) if err != nil { ReplyInternalError(w, fmt.Sprintf("Failed to read request body: %v", err)) return } start := time.Now() response, err := fn(w, r, mux.Vars(r), body) elapsedTime := time.Since(start) var status int if err != nil { response, status = responseAndStatusFor(err) } else { status = http.StatusOK } log.Infof("Request(Status=%v, Method=%v, Path=%v, Form=%v, Time=%v, Error=%v)", status, r.Method, r.URL, r.Form, elapsedTime, err) app.stats.TrackRequest(spec.MetricName, status, elapsedTime) Reply(w, response, status) } }
// RegisterApp adds a new backend and a single server with Vulcand. func (s *LeaderRegistry) RegisterApp(registration *AppRegistration) error { log.Infof("Registering app: %v", registration) endpoint, err := vulcan.NewEndpointWithID(s.Group, registration.Name, registration.Host, registration.Port) if err != nil { return err } err = s.client.RegisterBackend(endpoint) if err != nil { log.Errorf("Failed to register backend for endpoint: %v, %s", endpoint, err) return err } if s.IsMaster { err = s.maintainLeader(endpoint) } else { err = s.initLeader(endpoint) } if err != nil { log.Errorf("Failed to register server for endpoint: %v, %s", endpoint, err) return err } return nil }
// Start begins sending heartbeats. func (h *Heartbeater) Start() { log.Infof("Starting heartbeat for app: %v", h.registration) h.Running = true h.ticker = time.NewTicker(h.interval) h.quit = make(chan int) go h.heartbeat() }
func (s *LeaderRegistry) maintainLeader(endpoint *vulcan.Endpoint) error { err := s.client.UpdateServer(endpoint, s.TTL) if err != nil { log.Infof("Falling back to follow role for endpoint: %v", endpoint) s.IsMaster = false return err } return nil }
func (s *LeaderRegistry) initLeader(endpoint *vulcan.Endpoint) error { err := s.client.CreateServer(endpoint, s.TTL) if err != nil { return err } log.Infof("Assumed master role for endpoint: %v", endpoint) s.IsMaster = true return nil }
// Helper method to retrieve an optional timestamp from POST request field. // If no timestamp provided, returns current time. // Returns `InvalidFormatError` if provided timestamp can't be parsed. func GetTimestampField(r *http.Request, fieldName string) (time.Time, error) { if _, ok := r.Form[fieldName]; !ok { return time.Now(), MissingFieldError{fieldName} } parsedTime, err := time.Parse(time.RFC1123, r.FormValue(fieldName)) if err != nil { log.Infof("Failed to convert timestamp %v: %v", r.FormValue(fieldName), err) return time.Now(), InvalidFormatError{fieldName, r.FormValue(fieldName)} } return parsedTime, nil }
// registerLocationForHost registers a location for a specified hostname. func (app *App) registerLocationForHost(methods []string, path, host string, middlewares []middleware.Middleware) { r := ®istry.HandlerRegistration{ Name: app.Config.Name, Host: host, Path: path, Methods: methods, Middlewares: middlewares, } app.Config.Registry.RegisterHandler(r) log.Infof("Registered: %v", r) }
func (s *Service) reportSystemMetrics() { defer func() { if r := recover(); r != nil { log.Infof("Recovered in reportSystemMetrics", r) } }() for { s.metricsClient.ReportRuntimeMetrics("sys", 1.0) // we have 256 time buckets for gc stats, GC is being executed every 4ms on average // so we have 256 * 4 = 1024 around one second to report it. To play safe, let's report every 300ms time.Sleep(300 * time.Millisecond) } }
func Run() error { options, err := ParseCommandLine() if err != nil { return fmt.Errorf("failed to parse command line: %s", err) } service := NewService(options) if err := service.Start(); err != nil { log.Errorf("Failed to start service: %v", err) return fmt.Errorf("service start failure: %s", err) } else { log.Infof("Service exited gracefully") } return nil }
// RegisterHandler registers the frontends and middlewares with Vulcand. func (s *LeaderRegistry) RegisterHandler(registration *HandlerRegistration) error { log.Infof("Registering handler: %v", registration) location := vulcan.NewLocation(registration.Host, registration.Methods, registration.Path, registration.Name, registration.Middlewares) err := s.client.RegisterFrontend(location) if err != nil { log.Errorf("Failed to register frontend for location: %v, %s", location, err) return err } err = s.client.RegisterMiddleware(location) if err != nil { log.Errorf("Failed to register middleware for location: %v, %s", location, err) return err } return nil }
// RegisterApp adds a new backend and a single server with Vulcand. func (s *LBRegistry) RegisterApp(registration *AppRegistration) error { log.Infof("Registering app: %v", registration) endpoint, err := vulcan.NewEndpoint(registration.Name, registration.Host, registration.Port) if err != nil { return err } err = s.client.RegisterBackend(endpoint) if err != nil { log.Errorf("Failed to register backend for endpoint: %v, %s", endpoint, err) return err } err = s.client.UpsertServer(endpoint, s.TTL) if err != nil { log.Errorf("Failed to register server for endpoint: %v, %s", endpoint, err) return err } return nil }
func (c *ProxyController) handleError(w http.ResponseWriter, r *http.Request) { log.Infof("not found") scroll.ReplyError(w, scroll.NotFoundError{Description: "Object not found"}) }
// RegisterApp is a no-op. func (s *NopRegistry) RegisterApp(*AppRegistration) error { log.Infof("Skipping application registration for NopRegistry") return nil }
// RegisterHandler is a no-op. func (s *NopRegistry) RegisterHandler(*HandlerRegistration) error { log.Infof("Skipping handler registration for NopRegistry") return nil }
func (s *Service) Start() error { log.InitWithConfig(log.Config{ Name: s.options.Log, Severity: s.options.LogSeverity.S.String(), }) log.Infof("Service starts with options: %#v", s.options) if s.options.PidPath != "" { ioutil.WriteFile(s.options.PidPath, []byte(fmt.Sprint(os.Getpid())), 0644) } if s.options.StatsdAddr != "" { var err error s.metricsClient, err = metrics.NewWithOptions(s.options.StatsdAddr, s.options.StatsdPrefix, metrics.Options{UseBuffering: true}) if err != nil { return err } } // apiFile, muxFiles, err := s.getFiles() // if err != nil { // return err // } // if err := s.newEngine(); err != nil { // return err // } // s.stapler = stapler.New() // s.supervisor = supervisor.New( // s.newProxy, s.ng, s.errorC, supervisor.Options{Files: muxFiles}) // Tells configurator to perform initial proxy configuration and start watching changes // if err := s.supervisor.Start(); err != nil { // return err // } if err := s.newEngine(); err != nil { return err } if err := s.initApi(); err != nil { return err } go func() { s.errorC <- s.startApi() }() if s.metricsClient != nil { go s.reportSystemMetrics() } signal.Notify(s.sigC, os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGUSR2, syscall.SIGCHLD) // Block until a signal is received or we got an error for { select { case signal := <-s.sigC: switch signal { case syscall.SIGTERM, syscall.SIGINT: log.Infof("Got signal '%s', shutting down gracefully", signal) //s.supervisor.Stop(true) log.Infof("All servers stopped") return nil case syscall.SIGKILL: log.Infof("Got signal '%s', exiting now without waiting", signal) //s.supervisor.Stop(false) return nil default: log.Infof("Ignoring '%s'", signal) } case err := <-s.errorC: log.Infof("Got request to shutdown with error: %s", err) return err } } }