diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml new file mode 100644 index 0000000..b061bc8 --- /dev/null +++ b/.github/workflows/golangci-lint.yml @@ -0,0 +1,28 @@ +name: golangci-lint +on: + push: + tags: + - v* + branches: + - master + pull_request: +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: golangci-lint + uses: golangci/golangci-lint-action@v1 + with: + # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. + version: v1.26 + + # Optional: working directory, useful for monorepos + # working-directory: somedir + + # Optional: golangci-lint command line arguments. + # args: --issues-exit-code=0 + + # Optional: show only new issues if it's a pull request. The default value is `false`. + # only-new-issues: true diff --git a/Makefile b/Makefile index 340e878..f8952be 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,12 @@ RELEASE=$$(git rev-parse HEAD) default: bin +lint: + golangci-lint run + +lint-fix: + golangci-lint run --fix + bin: mkdir -p bin cd ./ && go build -o ./bin/$(APP_NAME) diff --git a/internal/connection/main.go b/internal/connection/main.go index 670bb3d..7d0c0e0 100644 --- a/internal/connection/main.go +++ b/internal/connection/main.go @@ -51,29 +51,25 @@ func (c *Connection) Get() (*httputil.ReverseProxy, error) { } func (c *Connection) healthCheck() { - for { - select { - case msg := <-c.Messages: - c.Lock() - if msg.Shutdown { - c.Shutdown() - c.Unlock() - return - } else { - backend := msg.Backend - c.healthy = msg.Health - proxy := msg.Proxy - - if proxy != nil && c.Backend != backend { - c.Backend = backend - c.proxy = proxy - } + for msg := range c.Messages { + c.Lock() + if msg.Shutdown { + c.Shutdown() + c.Unlock() + return + } else { + backend := msg.Backend + c.healthy = msg.Health + proxy := msg.Proxy + if proxy != nil && c.Backend != backend { + c.Backend = backend + c.proxy = proxy } - - msg.Ack.Done() - c.Unlock() } + + msg.Ack.Done() + c.Unlock() } } diff --git a/internal/connection/main_test.go b/internal/connection/main_test.go index 348b60e..d2f9374 100644 --- a/internal/connection/main_test.go +++ b/internal/connection/main_test.go @@ -1,6 +1,7 @@ package connection import ( + "log" "net/http" "net/http/httptest" "net/http/httputil" @@ -14,18 +15,21 @@ import ( ) func TestConnection(t *testing.T) { + assertion := &assert.Asserter{T: t} + tr := &http.Transport{ MaxIdleConns: 10, IdleConnTimeout: 1 * time.Second, } availableHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - var message []byte - message = []byte("hello") - w.Write(message) - }) + message := []byte("hello") - assertion := &assert.Asserter{T: t} + _, err := w.Write(message) + if err != nil { + log.Printf("Error writing: %s", err.Error()) + } + }) t.Run("When get is called on a healthy connection", func(t *testing.T) { availableServer := httptest.NewServer(availableHandler) diff --git a/internal/gracefulserver/main_test.go b/internal/gracefulserver/main_test.go index cec1649..116dc36 100644 --- a/internal/gracefulserver/main_test.go +++ b/internal/gracefulserver/main_test.go @@ -17,7 +17,10 @@ func TestMain(m *testing.M) { } func testHandler(rw http.ResponseWriter, req *http.Request) { - rw.Write([]byte("ok")) + _, err := rw.Write([]byte("ok")) + if err != nil { + log.Printf("Error writing: %s", err.Error()) + } } func TestListenAndServe(t *testing.T) { diff --git a/internal/healthcheck/main.go b/internal/healthcheck/main.go index a947171..a41c3a3 100644 --- a/internal/healthcheck/main.go +++ b/internal/healthcheck/main.go @@ -42,23 +42,19 @@ func New(client *http.Client, subscribers []chan connection.Message, backend str } func (hc *HealthChecker) Start(startup *sync.WaitGroup) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + bg := context.Background() + timeout := 1000 * time.Millisecond startup.Done() + ctx, cancel := context.WithTimeout(bg, timeout) + hc.check(ctx, cancel) - hc.Lock() - hc.check(ctx) - hc.Unlock() - - ticker := time.NewTicker(1000 * time.Millisecond) + ticker := time.NewTicker(timeout) for { select { - case <-ticker.C: - cancel() - hc.Lock() - ctx, cancel = context.WithCancel(context.Background()) - hc.check(ctx) - hc.Unlock() + case <-ctx.Done(): + <-ticker.C + ctx, cancel = context.WithTimeout(bg, timeout) + hc.check(ctx, cancel) case <-hc.done: ticker.Stop() return @@ -75,7 +71,11 @@ func (hc *HealthChecker) Reuse(newBackend string, proxy *httputil.ReverseProxy) return hc } -func (hc *HealthChecker) check(ctx context.Context) { +func (hc *HealthChecker) check(ctx context.Context, cancel context.CancelFunc) { + hc.Lock() + defer hc.Unlock() + defer cancel() + url := fmt.Sprintf("%s%s", hc.backend, "/health") var healthy bool diff --git a/internal/healthcheck/main_test.go b/internal/healthcheck/main_test.go index a38101d..bb66457 100644 --- a/internal/healthcheck/main_test.go +++ b/internal/healthcheck/main_test.go @@ -2,6 +2,7 @@ package healthcheck import ( "encoding/json" + "log" "net/http" "net/http/httptest" "sync" @@ -27,7 +28,10 @@ func TestHealthChecker(t *testing.T) { availableHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { healthReponse := &Reponse{State: "healthy", Message: ""} healthMessage, _ := json.Marshal(healthReponse) - w.Write(healthMessage) + _, err := w.Write(healthMessage) + if err != nil { + log.Printf("Error writing: %s", err.Error()) + } }) availableServer := httptest.NewServer(availableHandler) @@ -45,18 +49,15 @@ func TestHealthChecker(t *testing.T) { blocker := make(chan bool, 1) var msg connection.Message go func() { - for { - select { - case msg = <-resChan: - if !msg.Shutdown { - msg.Ack.Done() - blocker <- true - } + for msg = range resChan { + if !msg.Shutdown { + msg.Ack.Done() + blocker <- true } } }() - hc = hc.Reuse("foobar", nil) + _ = hc.Reuse("foobar", nil) <-blocker assertion.Equal(msg.Health, false) @@ -69,7 +70,10 @@ func TestHealthChecker(t *testing.T) { availableHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { healthReponse := &Reponse{State: "healthy", Message: ""} healthMessage, _ := json.Marshal(healthReponse) - w.Write(healthMessage) + _, err := w.Write(healthMessage) + if err != nil { + log.Printf("Error writing: %s", err.Error()) + } }) availableServer := httptest.NewServer(availableHandler) @@ -98,7 +102,10 @@ func TestHealthChecker(t *testing.T) { degradedHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { healthReponse := &Reponse{State: "degraded", Message: ""} healthMessage, _ := json.Marshal(healthReponse) - w.Write(healthMessage) + _, err := w.Write(healthMessage) + if err != nil { + log.Printf("Error writing: %s", err.Error()) + } }) degradedServer := httptest.NewServer(degradedHandler) diff --git a/internal/pool/main.go b/internal/pool/main.go index cc834f6..ecc3520 100644 --- a/internal/pool/main.go +++ b/internal/pool/main.go @@ -132,7 +132,10 @@ func (p *pool) Fetch(w http.ResponseWriter, r *http.Request) { if found { stats.CacheCounter.WithLabelValues("hit").Add(1) res := value.(string) - w.Write([]byte(res)) + _, err := w.Write([]byte(res)) + if err != nil { + log.Printf("Error writing: %s", err.Error()) + } return } diff --git a/internal/pool/main_test.go b/internal/pool/main_test.go index bec5c5a..0cca85d 100644 --- a/internal/pool/main_test.go +++ b/internal/pool/main_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io/ioutil" + "log" "net" "net/http" "net/http/httptest" @@ -29,7 +30,6 @@ func waitForHealthCheck(connectionPool *pool, server string) { } hc.Wg.Wait() - return } func TestFetch(t *testing.T) { @@ -66,7 +66,10 @@ func TestFetch(t *testing.T) { message = []byte("hello") } - w.Write(message) + _, err := w.Write(message) + if err != nil { + log.Printf("Error writing: %s", err.Error()) + } go func() { time.Sleep(1 * time.Second) @@ -120,7 +123,11 @@ func TestFetch(t *testing.T) { message = []byte("hello") } - w.Write(message) + _, err := w.Write(message) + if err != nil { + log.Printf("Error writing: %s", err.Error()) + } + go func() { time.Sleep(1 * time.Second) blocker <- true @@ -173,7 +180,11 @@ func TestFetch(t *testing.T) { message = []byte("hello") } - w.Write(message) + _, err := w.Write(message) + if err != nil { + log.Printf("Error writing: %s", err.Error()) + } + go func() { time.Sleep(1 * time.Second) blocker <- true @@ -229,7 +240,10 @@ func TestFetch(t *testing.T) { message = []byte("bar") } - w.Write(message) + _, err := w.Write(message) + if err != nil { + log.Printf("Error writing: %s", err.Error()) + } go func() { time.Sleep(1 * time.Second) blocker <- true