Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

indexserver: Wait for frontend to start #30

Merged
merged 2 commits into from
Oct 1, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions cmd/zoekt-sourcegraph-indexserver/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"flag"
"fmt"
"html/template"
"io"
"io/ioutil"
"log"
"math"
Expand Down Expand Up @@ -95,6 +96,8 @@ func (s *Server) loggedRun(tr trace.Trace, cmd *exec.Cmd) error {

// Run the sync loop. This blocks forever.
func (s *Server) Run() {
waitForFrontend(s.Root)

queue := &Queue{}

// Start a goroutine which updates the queue with commits to index.
Expand Down Expand Up @@ -408,6 +411,54 @@ func resolveRevision(root *url.URL, repo, spec string) (string, error) {
return b.String(), nil
}

func ping(root *url.URL) error {
u := root.ResolveReference(&url.URL{Path: "/.internal/ping"})
resp, err := http.Get(u.String())
if err != nil {
return err
}

defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("ping: bad HTTP response status %d", resp.StatusCode)
}
body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1024))
Copy link
Contributor

@kzh kzh Sep 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would changing 1024 to 16 allow us to avoid doing the truncating logic below?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes it would! will update.

if err != nil {
return err
}
if want := []byte("pong"); !bytes.Equal(body, want) {
const max = 15
if len(body) > max {
body = body[:max]
}
return fmt.Errorf("ping: bad HTTP response body %q (want %q)", string(body), string(want))
}
return nil
}

func waitForFrontend(root *url.URL) {
warned := false
lastWarn := time.Now()
for {
err := ping(root)
if err == nil {
break
}

if time.Since(lastWarn) > 15*time.Second {
warned = true
lastWarn = time.Now()
log.Printf("frontend API not reachable, will try again: %s", err)
}

time.Sleep(250 * time.Millisecond)
}

if warned {
log.Println("frontend API is now reachable. Starting indexing...")
}
}

func tarballURL(root *url.URL, repo, commit string) string {
return root.ResolveReference(&url.URL{Path: fmt.Sprintf("/.internal/git/%s/tar/%s", repo, commit)}).String()
}
Expand Down
46 changes: 46 additions & 0 deletions cmd/zoekt-sourcegraph-indexserver/main_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package main

import (
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"strings"
"testing"
"time"
)

func TestGetIndexOptions(t *testing.T) {
Expand Down Expand Up @@ -84,3 +87,46 @@ func TestListRepos(t *testing.T) {
t.Fatalf("unexpected request path. got %q, want %q", gotURL.Path, want)
}
}

func TestPing(t *testing.T) {
var response []byte
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/.internal/ping" {
http.Error(w, "not found", http.StatusNotFound)
return
}
_, _ = w.Write(response)
}))
defer server.Close()

root, err := url.Parse(server.URL)
if err != nil {
t.Fatal(err)
}

// Ping fails
response = []byte("hello")
err = ping(root)
if got, want := fmt.Sprintf("%v", err), "bad HTTP response body"; !strings.Contains(got, want) {
t.Errorf("wanted ping to fail,\ngot: %q\nwant: %q", got, want)
}

response = []byte("pong")
err = ping(root)
if err != nil {
t.Errorf("wanted ping to succeed, got: %v", err)
}

// We expect waitForFrontend to just work now
done := make(chan struct{})
go func() {
waitForFrontend(root)
close(done)
}()

select {
case <-done:
case <-time.After(5 * time.Second):
t.Fatal("waitForFrontend blocking")
}
}