Skip to content

Commit

Permalink
Merge pull request hound-search#297 from etsy/health-check
Browse files Browse the repository at this point in the history
Add the ability to respond to health checks prior to indexes being built.
  • Loading branch information
kellegous committed Nov 2, 2018
2 parents c3ae284 + a22cb80 commit 27ed6d2
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 25 deletions.
9 changes: 6 additions & 3 deletions cmds/houndd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/etsy/hound/config"
"github.com/etsy/hound/searcher"
"github.com/etsy/hound/ui"
"github.com/etsy/hound/web"
)

const gracefulShutdownSignal = syscall.SIGTERM
Expand Down Expand Up @@ -128,6 +129,9 @@ func main() {
panic(err)
}

// Start the web server on a background routine.
ws := web.Start(&cfg, *flagAddr, *flagDev)

// It's not safe to be killed during makeSearchers, so register the
// shutdown signal here and defer processing it until we are ready.
shutdownCh := registerShutdownSignal()
Expand Down Expand Up @@ -162,7 +166,6 @@ func main() {

info_log.Printf("running server at http://%s...\n", host)

if err := runHttp(*flagAddr, *flagDev, &cfg, idx); err != nil {
panic(err)
}
// Fully enable the web server now that we have indexes
panic(ws.ServeWithIndex(idx))
}
6 changes: 6 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const (
defaultVcs = "git"
defaultBaseUrl = "{url}/blob/master/{path}{anchor}"
defaultAnchor = "#L{line}"
defaultHealthChekURI = "/healthz"
)

type UrlPattern struct {
Expand Down Expand Up @@ -56,6 +57,7 @@ type Config struct {
DbPath string `json:"dbpath"`
Repos map[string]*Repo `json:"repos"`
MaxConcurrentIndexers int `json:"max-concurrent-indexers"`
HealthCheckURI string `json:"health-check-uri"`
}

// SecretMessage is just like json.RawMessage but it will not
Expand Down Expand Up @@ -117,6 +119,10 @@ func initConfig(c *Config) {
if c.MaxConcurrentIndexers == 0 {
c.MaxConcurrentIndexers = defaultMaxConcurrentIndexers
}

if c.HealthCheckURI == "" {
c.HealthCheckURI = defaultHealthChekURI
}
}

func (c *Config) LoadFromFile(filename string) error {
Expand Down
44 changes: 22 additions & 22 deletions ui/bindata.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

85 changes: 85 additions & 0 deletions web/web.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package web

import (
"fmt"
"net/http"
"sync"

"github.com/etsy/hound/api"
"github.com/etsy/hound/config"
"github.com/etsy/hound/searcher"
"github.com/etsy/hound/ui"
)

// Server is an HTTP server that handles all
// http traffic for hound. It is able to serve
// some traffic before indexes are built and
// then transition to all traffic afterwards.
type Server struct {
cfg *config.Config
dev bool
ch chan error

mux *http.ServeMux
lck sync.RWMutex
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == s.cfg.HealthCheckURI {
fmt.Fprintln(w, "👍")
return
}

s.lck.RLock()
defer s.lck.RUnlock()
if m := s.mux; m != nil {
m.ServeHTTP(w, r)
} else {
http.Error(w,
"Hound is not ready.",
http.StatusServiceUnavailable)
}
}

func (s *Server) serveWith(m *http.ServeMux) {
s.lck.Lock()
defer s.lck.Unlock()
s.mux = m
}

// Start creates a new server that will immediately start handling HTTP traffic.
// The HTTP server will return 200 on the health check, but a 503 on every other
// request until ServeWithIndex is called to begin serving search traffic with
// the given searchers.
func Start(cfg *config.Config, addr string, dev bool) *Server {
ch := make(chan error)

s := &Server{
cfg: cfg,
dev: dev,
ch: ch,
}

go func() {
ch <- http.ListenAndServe(addr, s)
}()

return s
}

// ServeWithIndex allow the server to start offering the search UI and the
// search APIs operating on the given indexes.
func (s *Server) ServeWithIndex(idx map[string]*searcher.Searcher) error {
h, err := ui.Content(s.dev, s.cfg)
if err != nil {
return err
}

m := http.NewServeMux()
m.Handle("/", h)
api.Setup(m, idx)

s.serveWith(m)

return <-s.ch
}

0 comments on commit 27ed6d2

Please sign in to comment.